mirror of
https://github.com/vim/vim.git
synced 2025-07-26 11:04:33 -04:00
patch 7.4.2137
Problem: Using function() with a name will find another function when it is redefined. Solution: Add funcref(). Refer to lambda using a partial. Fix several reference counting issues.
This commit is contained in:
parent
5801644819
commit
437bafe4c8
@ -1,4 +1,4 @@
|
|||||||
*eval.txt* For Vim version 7.4. Last change: 2016 Jul 29
|
*eval.txt* For Vim version 7.4. Last change: 2016 Jul 31
|
||||||
|
|
||||||
|
|
||||||
VIM REFERENCE MANUAL by Bram Moolenaar
|
VIM REFERENCE MANUAL by Bram Moolenaar
|
||||||
@ -1240,7 +1240,9 @@ function returns: >
|
|||||||
:let Bar = Foo(4)
|
:let Bar = Foo(4)
|
||||||
:echo Bar(6)
|
:echo Bar(6)
|
||||||
< 5
|
< 5
|
||||||
See also |:func-closure|.
|
|
||||||
|
See also |:func-closure|. Lambda and closure support can be checked with: >
|
||||||
|
if has('lambda')
|
||||||
|
|
||||||
Examples for using a lambda expression with |sort()|, |map()| and |filter()|: >
|
Examples for using a lambda expression with |sort()|, |map()| and |filter()|: >
|
||||||
:echo map([1, 2, 3], {idx, val -> val + 1})
|
:echo map([1, 2, 3], {idx, val -> val + 1})
|
||||||
@ -2071,8 +2073,10 @@ foldlevel({lnum}) Number fold level at {lnum}
|
|||||||
foldtext() String line displayed for closed fold
|
foldtext() String line displayed for closed fold
|
||||||
foldtextresult({lnum}) String text for closed fold at {lnum}
|
foldtextresult({lnum}) String text for closed fold at {lnum}
|
||||||
foreground() Number bring the Vim window to the foreground
|
foreground() Number bring the Vim window to the foreground
|
||||||
function({name} [, {arglist}] [, {dict}])
|
funcref({name} [, {arglist}] [, {dict}])
|
||||||
Funcref reference to function {name}
|
Funcref reference to function {name}
|
||||||
|
function({name} [, {arglist}] [, {dict}])
|
||||||
|
Funcref named reference to function {name}
|
||||||
garbagecollect([{atexit}]) none free memory, breaking cyclic references
|
garbagecollect([{atexit}]) none free memory, breaking cyclic references
|
||||||
get({list}, {idx} [, {def}]) any get item {idx} from {list} or {def}
|
get({list}, {idx} [, {def}]) any get item {idx} from {list} or {def}
|
||||||
get({dict}, {key} [, {def}]) any get item {key} from {dict} or {def}
|
get({dict}, {key} [, {def}]) any get item {key} from {dict} or {def}
|
||||||
@ -3850,6 +3854,15 @@ foreground() Move the Vim window to the foreground. Useful when sent from
|
|||||||
{only in the Win32, Athena, Motif and GTK GUI versions and the
|
{only in the Win32, Athena, Motif and GTK GUI versions and the
|
||||||
Win32 console version}
|
Win32 console version}
|
||||||
|
|
||||||
|
*funcref()*
|
||||||
|
funcref({name} [, {arglist}] [, {dict}])
|
||||||
|
Just like |function()|, but the returned Funcref will lookup
|
||||||
|
the function by reference, not by name. This matters when the
|
||||||
|
function {name} is redefined later.
|
||||||
|
|
||||||
|
Unlike |function()|, {name} must be an existing user function.
|
||||||
|
Also for autoloaded functions. {name} cannot be a builtin
|
||||||
|
function.
|
||||||
|
|
||||||
*function()* *E700* *E922* *E923*
|
*function()* *E700* *E922* *E923*
|
||||||
function({name} [, {arglist}] [, {dict}])
|
function({name} [, {arglist}] [, {dict}])
|
||||||
@ -3857,12 +3870,16 @@ function({name} [, {arglist}] [, {dict}])
|
|||||||
{name} can be the name of a user defined function or an
|
{name} can be the name of a user defined function or an
|
||||||
internal function.
|
internal function.
|
||||||
|
|
||||||
{name} can also be a Funcref, also a partial. When it is a
|
{name} can also be a Funcref or a partial. When it is a
|
||||||
partial the dict stored in it will be used and the {dict}
|
partial the dict stored in it will be used and the {dict}
|
||||||
argument is not allowed. E.g.: >
|
argument is not allowed. E.g.: >
|
||||||
let FuncWithArg = function(dict.Func, [arg])
|
let FuncWithArg = function(dict.Func, [arg])
|
||||||
let Broken = function(dict.Func, [arg], dict)
|
let Broken = function(dict.Func, [arg], dict)
|
||||||
<
|
<
|
||||||
|
When using the Funcref the function will be found by {name},
|
||||||
|
also when it was redefined later. Use |funcref()| to keep the
|
||||||
|
same function.
|
||||||
|
|
||||||
When {arglist} or {dict} is present this creates a partial.
|
When {arglist} or {dict} is present this creates a partial.
|
||||||
That means the argument list and/or the dictionary is stored in
|
That means the argument list and/or the dictionary is stored in
|
||||||
the Funcref and will be used when the Funcref is called.
|
the Funcref and will be used when the Funcref is called.
|
||||||
@ -6191,6 +6208,7 @@ screenrow() *screenrow()*
|
|||||||
The result is a Number, which is the current screen row of the
|
The result is a Number, which is the current screen row of the
|
||||||
cursor. The top line has number one.
|
cursor. The top line has number one.
|
||||||
This function is mainly used for testing.
|
This function is mainly used for testing.
|
||||||
|
Alternatively you can use |winline()|.
|
||||||
|
|
||||||
Note: Same restrictions as with |screencol()|.
|
Note: Same restrictions as with |screencol()|.
|
||||||
|
|
||||||
@ -8039,6 +8057,7 @@ insert_expand Compiled with support for CTRL-X expansion commands in
|
|||||||
Insert mode.
|
Insert mode.
|
||||||
jumplist Compiled with |jumplist| support.
|
jumplist Compiled with |jumplist| support.
|
||||||
keymap Compiled with 'keymap' support.
|
keymap Compiled with 'keymap' support.
|
||||||
|
lambda Compiled with |lambda| support.
|
||||||
langmap Compiled with 'langmap' support.
|
langmap Compiled with 'langmap' support.
|
||||||
libcall Compiled with |libcall()| support.
|
libcall Compiled with |libcall()| support.
|
||||||
linebreak Compiled with 'linebreak', 'breakat', 'showbreak' and
|
linebreak Compiled with 'linebreak', 'breakat', 'showbreak' and
|
||||||
@ -8294,7 +8313,7 @@ See |:verbose-cmd| for more information.
|
|||||||
:endf[unction] The end of a function definition. Must be on a line
|
:endf[unction] The end of a function definition. Must be on a line
|
||||||
by its own, without other commands.
|
by its own, without other commands.
|
||||||
|
|
||||||
*:delf* *:delfunction* *E130* *E131*
|
*:delf* *:delfunction* *E130* *E131* *E933*
|
||||||
:delf[unction] {name} Delete function {name}.
|
:delf[unction] {name} Delete function {name}.
|
||||||
{name} can also be a |Dictionary| entry that is a
|
{name} can also be a |Dictionary| entry that is a
|
||||||
|Funcref|: >
|
|Funcref|: >
|
||||||
|
@ -1124,15 +1124,18 @@ set_callback(
|
|||||||
if (callback != NULL && *callback != NUL)
|
if (callback != NULL && *callback != NUL)
|
||||||
{
|
{
|
||||||
if (partial != NULL)
|
if (partial != NULL)
|
||||||
*cbp = partial->pt_name;
|
*cbp = partial_name(partial);
|
||||||
else
|
else
|
||||||
|
{
|
||||||
*cbp = vim_strsave(callback);
|
*cbp = vim_strsave(callback);
|
||||||
|
func_ref(*cbp);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
*cbp = NULL;
|
*cbp = NULL;
|
||||||
*pp = partial;
|
*pp = partial;
|
||||||
if (*pp != NULL)
|
if (partial != NULL)
|
||||||
++(*pp)->pt_refcount;
|
++partial->pt_refcount;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1279,7 +1282,10 @@ channel_set_req_callback(
|
|||||||
item->cq_callback = callback;
|
item->cq_callback = callback;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
item->cq_callback = vim_strsave(callback);
|
item->cq_callback = vim_strsave(callback);
|
||||||
|
func_ref(item->cq_callback);
|
||||||
|
}
|
||||||
item->cq_seq_nr = id;
|
item->cq_seq_nr = id;
|
||||||
item->cq_prev = head->cq_prev;
|
item->cq_prev = head->cq_prev;
|
||||||
head->cq_prev = item;
|
head->cq_prev = item;
|
||||||
@ -3923,14 +3929,24 @@ free_job_options(jobopt_T *opt)
|
|||||||
{
|
{
|
||||||
if (opt->jo_partial != NULL)
|
if (opt->jo_partial != NULL)
|
||||||
partial_unref(opt->jo_partial);
|
partial_unref(opt->jo_partial);
|
||||||
|
else if (opt->jo_callback != NULL)
|
||||||
|
func_unref(opt->jo_callback);
|
||||||
if (opt->jo_out_partial != NULL)
|
if (opt->jo_out_partial != NULL)
|
||||||
partial_unref(opt->jo_out_partial);
|
partial_unref(opt->jo_out_partial);
|
||||||
|
else if (opt->jo_out_cb != NULL)
|
||||||
|
func_unref(opt->jo_out_cb);
|
||||||
if (opt->jo_err_partial != NULL)
|
if (opt->jo_err_partial != NULL)
|
||||||
partial_unref(opt->jo_err_partial);
|
partial_unref(opt->jo_err_partial);
|
||||||
|
else if (opt->jo_err_cb != NULL)
|
||||||
|
func_unref(opt->jo_err_cb);
|
||||||
if (opt->jo_close_partial != NULL)
|
if (opt->jo_close_partial != NULL)
|
||||||
partial_unref(opt->jo_close_partial);
|
partial_unref(opt->jo_close_partial);
|
||||||
|
else if (opt->jo_close_cb != NULL)
|
||||||
|
func_unref(opt->jo_close_cb);
|
||||||
if (opt->jo_exit_partial != NULL)
|
if (opt->jo_exit_partial != NULL)
|
||||||
partial_unref(opt->jo_exit_partial);
|
partial_unref(opt->jo_exit_partial);
|
||||||
|
else if (opt->jo_exit_cb != NULL)
|
||||||
|
func_unref(opt->jo_exit_cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -4476,7 +4492,10 @@ job_set_options(job_T *job, jobopt_T *opt)
|
|||||||
++job->jv_exit_partial->pt_refcount;
|
++job->jv_exit_partial->pt_refcount;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
job->jv_exit_cb = vim_strsave(opt->jo_exit_cb);
|
job->jv_exit_cb = vim_strsave(opt->jo_exit_cb);
|
||||||
|
func_ref(job->jv_exit_cb);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
34
src/eval.c
34
src/eval.c
@ -5011,6 +5011,17 @@ get_lit_string_tv(char_u **arg, typval_T *rettv, int evaluate)
|
|||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return the function name of the partial.
|
||||||
|
*/
|
||||||
|
char_u *
|
||||||
|
partial_name(partial_T *pt)
|
||||||
|
{
|
||||||
|
if (pt->pt_name != NULL)
|
||||||
|
return pt->pt_name;
|
||||||
|
return pt->pt_func->uf_name;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
partial_free(partial_T *pt)
|
partial_free(partial_T *pt)
|
||||||
{
|
{
|
||||||
@ -5020,8 +5031,13 @@ partial_free(partial_T *pt)
|
|||||||
clear_tv(&pt->pt_argv[i]);
|
clear_tv(&pt->pt_argv[i]);
|
||||||
vim_free(pt->pt_argv);
|
vim_free(pt->pt_argv);
|
||||||
dict_unref(pt->pt_dict);
|
dict_unref(pt->pt_dict);
|
||||||
func_unref(pt->pt_name);
|
if (pt->pt_name != NULL)
|
||||||
vim_free(pt->pt_name);
|
{
|
||||||
|
func_unref(pt->pt_name);
|
||||||
|
vim_free(pt->pt_name);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
func_ptr_unref(pt->pt_func);
|
||||||
vim_free(pt);
|
vim_free(pt);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5051,11 +5067,11 @@ func_equal(
|
|||||||
|
|
||||||
/* empty and NULL function name considered the same */
|
/* empty and NULL function name considered the same */
|
||||||
s1 = tv1->v_type == VAR_FUNC ? tv1->vval.v_string
|
s1 = tv1->v_type == VAR_FUNC ? tv1->vval.v_string
|
||||||
: tv1->vval.v_partial->pt_name;
|
: partial_name(tv1->vval.v_partial);
|
||||||
if (s1 != NULL && *s1 == NUL)
|
if (s1 != NULL && *s1 == NUL)
|
||||||
s1 = NULL;
|
s1 = NULL;
|
||||||
s2 = tv2->v_type == VAR_FUNC ? tv2->vval.v_string
|
s2 = tv2->v_type == VAR_FUNC ? tv2->vval.v_string
|
||||||
: tv2->vval.v_partial->pt_name;
|
: partial_name(tv2->vval.v_partial);
|
||||||
if (s2 != NULL && *s2 == NUL)
|
if (s2 != NULL && *s2 == NUL)
|
||||||
s2 = NULL;
|
s2 = NULL;
|
||||||
if (s1 == NULL || s2 == NULL)
|
if (s1 == NULL || s2 == NULL)
|
||||||
@ -5550,7 +5566,7 @@ set_ref_in_item(
|
|||||||
}
|
}
|
||||||
else if (tv->v_type == VAR_FUNC)
|
else if (tv->v_type == VAR_FUNC)
|
||||||
{
|
{
|
||||||
abort = set_ref_in_func(tv->vval.v_string, copyID);
|
abort = set_ref_in_func(tv->vval.v_string, NULL, copyID);
|
||||||
}
|
}
|
||||||
else if (tv->v_type == VAR_PARTIAL)
|
else if (tv->v_type == VAR_PARTIAL)
|
||||||
{
|
{
|
||||||
@ -5561,7 +5577,7 @@ set_ref_in_item(
|
|||||||
*/
|
*/
|
||||||
if (pt != NULL)
|
if (pt != NULL)
|
||||||
{
|
{
|
||||||
abort = set_ref_in_func(pt->pt_name, copyID);
|
abort = set_ref_in_func(pt->pt_name, pt->pt_func, copyID);
|
||||||
|
|
||||||
if (pt->pt_dict != NULL)
|
if (pt->pt_dict != NULL)
|
||||||
{
|
{
|
||||||
@ -5735,7 +5751,7 @@ echo_string_core(
|
|||||||
{
|
{
|
||||||
partial_T *pt = tv->vval.v_partial;
|
partial_T *pt = tv->vval.v_partial;
|
||||||
char_u *fname = string_quote(pt == NULL ? NULL
|
char_u *fname = string_quote(pt == NULL ? NULL
|
||||||
: pt->pt_name, FALSE);
|
: partial_name(pt), FALSE);
|
||||||
garray_T ga;
|
garray_T ga;
|
||||||
int i;
|
int i;
|
||||||
char_u *tf;
|
char_u *tf;
|
||||||
@ -6871,7 +6887,7 @@ handle_subscript(
|
|||||||
if (functv.v_type == VAR_PARTIAL)
|
if (functv.v_type == VAR_PARTIAL)
|
||||||
{
|
{
|
||||||
pt = functv.vval.v_partial;
|
pt = functv.vval.v_partial;
|
||||||
s = pt->pt_name;
|
s = partial_name(pt);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
s = functv.vval.v_string;
|
s = functv.vval.v_string;
|
||||||
@ -10025,7 +10041,7 @@ filter_map_one(typval_T *tv, typval_T *expr, int map, int *remp)
|
|||||||
{
|
{
|
||||||
partial_T *partial = expr->vval.v_partial;
|
partial_T *partial = expr->vval.v_partial;
|
||||||
|
|
||||||
s = partial->pt_name;
|
s = partial_name(partial);
|
||||||
if (call_func(s, (int)STRLEN(s), &rettv, 2, argv, NULL,
|
if (call_func(s, (int)STRLEN(s), &rettv, 2, argv, NULL,
|
||||||
0L, 0L, &dummy, TRUE, partial, NULL) == FAIL)
|
0L, 0L, &dummy, TRUE, partial, NULL) == FAIL)
|
||||||
goto theend;
|
goto theend;
|
||||||
|
107
src/evalfunc.c
107
src/evalfunc.c
@ -148,6 +148,7 @@ static void f_foldlevel(typval_T *argvars, typval_T *rettv);
|
|||||||
static void f_foldtext(typval_T *argvars, typval_T *rettv);
|
static void f_foldtext(typval_T *argvars, typval_T *rettv);
|
||||||
static void f_foldtextresult(typval_T *argvars, typval_T *rettv);
|
static void f_foldtextresult(typval_T *argvars, typval_T *rettv);
|
||||||
static void f_foreground(typval_T *argvars, typval_T *rettv);
|
static void f_foreground(typval_T *argvars, typval_T *rettv);
|
||||||
|
static void f_funcref(typval_T *argvars, typval_T *rettv);
|
||||||
static void f_function(typval_T *argvars, typval_T *rettv);
|
static void f_function(typval_T *argvars, typval_T *rettv);
|
||||||
static void f_garbagecollect(typval_T *argvars, typval_T *rettv);
|
static void f_garbagecollect(typval_T *argvars, typval_T *rettv);
|
||||||
static void f_get(typval_T *argvars, typval_T *rettv);
|
static void f_get(typval_T *argvars, typval_T *rettv);
|
||||||
@ -563,6 +564,7 @@ static struct fst
|
|||||||
{"foldtext", 0, 0, f_foldtext},
|
{"foldtext", 0, 0, f_foldtext},
|
||||||
{"foldtextresult", 1, 1, f_foldtextresult},
|
{"foldtextresult", 1, 1, f_foldtextresult},
|
||||||
{"foreground", 0, 0, f_foreground},
|
{"foreground", 0, 0, f_foreground},
|
||||||
|
{"funcref", 1, 3, f_funcref},
|
||||||
{"function", 1, 3, f_function},
|
{"function", 1, 3, f_function},
|
||||||
{"garbagecollect", 0, 1, f_garbagecollect},
|
{"garbagecollect", 0, 1, f_garbagecollect},
|
||||||
{"get", 2, 3, f_get},
|
{"get", 2, 3, f_get},
|
||||||
@ -1723,7 +1725,7 @@ f_call(typval_T *argvars, typval_T *rettv)
|
|||||||
else if (argvars[0].v_type == VAR_PARTIAL)
|
else if (argvars[0].v_type == VAR_PARTIAL)
|
||||||
{
|
{
|
||||||
partial = argvars[0].vval.v_partial;
|
partial = argvars[0].vval.v_partial;
|
||||||
func = partial->pt_name;
|
func = partial_name(partial);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
func = get_tv_string(&argvars[0]);
|
func = get_tv_string(&argvars[0]);
|
||||||
@ -3543,16 +3545,14 @@ f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* "function()" function
|
|
||||||
*/
|
|
||||||
static void
|
static void
|
||||||
f_function(typval_T *argvars, typval_T *rettv)
|
common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
|
||||||
{
|
{
|
||||||
char_u *s;
|
char_u *s;
|
||||||
char_u *name;
|
char_u *name;
|
||||||
int use_string = FALSE;
|
int use_string = FALSE;
|
||||||
partial_T *arg_pt = NULL;
|
partial_T *arg_pt = NULL;
|
||||||
|
char_u *trans_name = NULL;
|
||||||
|
|
||||||
if (argvars[0].v_type == VAR_FUNC)
|
if (argvars[0].v_type == VAR_FUNC)
|
||||||
{
|
{
|
||||||
@ -3564,7 +3564,7 @@ f_function(typval_T *argvars, typval_T *rettv)
|
|||||||
{
|
{
|
||||||
/* function(dict.MyFunc, [arg]) */
|
/* function(dict.MyFunc, [arg]) */
|
||||||
arg_pt = argvars[0].vval.v_partial;
|
arg_pt = argvars[0].vval.v_partial;
|
||||||
s = arg_pt->pt_name;
|
s = partial_name(arg_pt);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -3573,11 +3573,22 @@ f_function(typval_T *argvars, typval_T *rettv)
|
|||||||
use_string = TRUE;
|
use_string = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL)
|
||||||
|
|| is_funcref))
|
||||||
|
{
|
||||||
|
name = s;
|
||||||
|
trans_name = trans_function_name(&name, FALSE,
|
||||||
|
TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL);
|
||||||
|
if (*name != NUL)
|
||||||
|
s = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s)))
|
if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s)))
|
||||||
EMSG2(_(e_invarg2), s);
|
EMSG2(_(e_invarg2), s);
|
||||||
/* Don't check an autoload name for existence here. */
|
/* Don't check an autoload name for existence here. */
|
||||||
else if (use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL
|
else if (trans_name != NULL && (is_funcref
|
||||||
&& !function_exists(s, TRUE))
|
? find_func(trans_name) == NULL
|
||||||
|
: !translated_function_exists(trans_name)))
|
||||||
EMSG2(_("E700: Unknown function: %s"), s);
|
EMSG2(_("E700: Unknown function: %s"), s);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -3625,7 +3636,7 @@ f_function(typval_T *argvars, typval_T *rettv)
|
|||||||
{
|
{
|
||||||
EMSG(_("E922: expected a dict"));
|
EMSG(_("E922: expected a dict"));
|
||||||
vim_free(name);
|
vim_free(name);
|
||||||
return;
|
goto theend;
|
||||||
}
|
}
|
||||||
if (argvars[dict_idx].vval.v_dict == NULL)
|
if (argvars[dict_idx].vval.v_dict == NULL)
|
||||||
dict_idx = 0;
|
dict_idx = 0;
|
||||||
@ -3636,14 +3647,14 @@ f_function(typval_T *argvars, typval_T *rettv)
|
|||||||
{
|
{
|
||||||
EMSG(_("E923: Second argument of function() must be a list or a dict"));
|
EMSG(_("E923: Second argument of function() must be a list or a dict"));
|
||||||
vim_free(name);
|
vim_free(name);
|
||||||
return;
|
goto theend;
|
||||||
}
|
}
|
||||||
list = argvars[arg_idx].vval.v_list;
|
list = argvars[arg_idx].vval.v_list;
|
||||||
if (list == NULL || list->lv_len == 0)
|
if (list == NULL || list->lv_len == 0)
|
||||||
arg_idx = 0;
|
arg_idx = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL)
|
if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL || is_funcref)
|
||||||
{
|
{
|
||||||
partial_T *pt = (partial_T *)alloc_clear(sizeof(partial_T));
|
partial_T *pt = (partial_T *)alloc_clear(sizeof(partial_T));
|
||||||
|
|
||||||
@ -3670,17 +3681,14 @@ f_function(typval_T *argvars, typval_T *rettv)
|
|||||||
{
|
{
|
||||||
vim_free(pt);
|
vim_free(pt);
|
||||||
vim_free(name);
|
vim_free(name);
|
||||||
return;
|
goto theend;
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for (i = 0; i < arg_len; i++)
|
|
||||||
copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
|
|
||||||
if (lv_len > 0)
|
|
||||||
for (li = list->lv_first; li != NULL;
|
|
||||||
li = li->li_next)
|
|
||||||
copy_tv(&li->li_tv, &pt->pt_argv[i++]);
|
|
||||||
}
|
}
|
||||||
|
for (i = 0; i < arg_len; i++)
|
||||||
|
copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
|
||||||
|
if (lv_len > 0)
|
||||||
|
for (li = list->lv_first; li != NULL;
|
||||||
|
li = li->li_next)
|
||||||
|
copy_tv(&li->li_tv, &pt->pt_argv[i++]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* For "function(dict.func, [], dict)" and "func" is a partial
|
/* For "function(dict.func, [], dict)" and "func" is a partial
|
||||||
@ -3702,8 +3710,23 @@ f_function(typval_T *argvars, typval_T *rettv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
pt->pt_refcount = 1;
|
pt->pt_refcount = 1;
|
||||||
pt->pt_name = name;
|
if (arg_pt != NULL && arg_pt->pt_func != NULL)
|
||||||
func_ref(pt->pt_name);
|
{
|
||||||
|
pt->pt_func = arg_pt->pt_func;
|
||||||
|
func_ptr_ref(pt->pt_func);
|
||||||
|
vim_free(name);
|
||||||
|
}
|
||||||
|
else if (is_funcref)
|
||||||
|
{
|
||||||
|
pt->pt_func = find_func(trans_name);
|
||||||
|
func_ptr_ref(pt->pt_func);
|
||||||
|
vim_free(name);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pt->pt_name = name;
|
||||||
|
func_ref(name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
rettv->v_type = VAR_PARTIAL;
|
rettv->v_type = VAR_PARTIAL;
|
||||||
rettv->vval.v_partial = pt;
|
rettv->vval.v_partial = pt;
|
||||||
@ -3716,6 +3739,26 @@ f_function(typval_T *argvars, typval_T *rettv)
|
|||||||
func_ref(name);
|
func_ref(name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
theend:
|
||||||
|
vim_free(trans_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* "funcref()" function
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
f_funcref(typval_T *argvars, typval_T *rettv)
|
||||||
|
{
|
||||||
|
common_function(argvars, rettv, TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* "function()" function
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
f_function(typval_T *argvars, typval_T *rettv)
|
||||||
|
{
|
||||||
|
common_function(argvars, rettv, FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -3781,14 +3824,20 @@ f_get(typval_T *argvars, typval_T *rettv)
|
|||||||
if (pt != NULL)
|
if (pt != NULL)
|
||||||
{
|
{
|
||||||
char_u *what = get_tv_string(&argvars[1]);
|
char_u *what = get_tv_string(&argvars[1]);
|
||||||
|
char_u *n;
|
||||||
|
|
||||||
if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0)
|
if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0)
|
||||||
{
|
{
|
||||||
rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING);
|
rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING);
|
||||||
if (pt->pt_name == NULL)
|
n = partial_name(pt);
|
||||||
|
if (n == NULL)
|
||||||
rettv->vval.v_string = NULL;
|
rettv->vval.v_string = NULL;
|
||||||
else
|
else
|
||||||
rettv->vval.v_string = vim_strsave(pt->pt_name);
|
{
|
||||||
|
rettv->vval.v_string = vim_strsave(n);
|
||||||
|
if (rettv->v_type == VAR_FUNC)
|
||||||
|
func_ref(rettv->vval.v_string);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (STRCMP(what, "dict") == 0)
|
else if (STRCMP(what, "dict") == 0)
|
||||||
{
|
{
|
||||||
@ -10104,7 +10153,7 @@ item_compare2(const void *s1, const void *s2)
|
|||||||
if (partial == NULL)
|
if (partial == NULL)
|
||||||
func_name = sortinfo->item_compare_func;
|
func_name = sortinfo->item_compare_func;
|
||||||
else
|
else
|
||||||
func_name = partial->pt_name;
|
func_name = partial_name(partial);
|
||||||
|
|
||||||
/* Copy the values. This is needed to be able to set v_lock to VAR_FIXED
|
/* Copy the values. This is needed to be able to set v_lock to VAR_FIXED
|
||||||
* in the copy without changing the original list items. */
|
* in the copy without changing the original list items. */
|
||||||
@ -11863,16 +11912,14 @@ get_callback(typval_T *arg, partial_T **pp)
|
|||||||
{
|
{
|
||||||
*pp = arg->vval.v_partial;
|
*pp = arg->vval.v_partial;
|
||||||
++(*pp)->pt_refcount;
|
++(*pp)->pt_refcount;
|
||||||
return (*pp)->pt_name;
|
return partial_name(*pp);
|
||||||
}
|
}
|
||||||
*pp = NULL;
|
*pp = NULL;
|
||||||
if (arg->v_type == VAR_FUNC)
|
if (arg->v_type == VAR_FUNC || arg->v_type == VAR_STRING)
|
||||||
{
|
{
|
||||||
func_ref(arg->vval.v_string);
|
func_ref(arg->vval.v_string);
|
||||||
return arg->vval.v_string;
|
return arg->vval.v_string;
|
||||||
}
|
}
|
||||||
if (arg->v_type == VAR_STRING)
|
|
||||||
return arg->vval.v_string;
|
|
||||||
if (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0)
|
if (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0)
|
||||||
return (char_u *)"";
|
return (char_u *)"";
|
||||||
EMSG(_("E921: Invalid callback argument"));
|
EMSG(_("E921: Invalid callback argument"));
|
||||||
|
@ -3134,7 +3134,7 @@ vim_to_mzscheme_impl(typval_T *vim_value, int depth, Scheme_Hash_Table *visited)
|
|||||||
/* FIXME: func_ref() and func_unref() are needed. */
|
/* FIXME: func_ref() and func_unref() are needed. */
|
||||||
/* TODO: Support pt_dict and pt_argv. */
|
/* TODO: Support pt_dict and pt_argv. */
|
||||||
funcname = scheme_make_byte_string(
|
funcname = scheme_make_byte_string(
|
||||||
(char *)vim_value->vval.v_partial->pt_name);
|
(char *)partial_name(vim_value->vval.v_partial));
|
||||||
MZ_GC_CHECK();
|
MZ_GC_CHECK();
|
||||||
result = scheme_make_closed_prim_w_arity(vim_funcref, funcname,
|
result = scheme_make_closed_prim_w_arity(vim_funcref, funcname,
|
||||||
(const char *)BYTE_STRING_VALUE(funcname), 0, -1);
|
(const char *)BYTE_STRING_VALUE(funcname), 0, -1);
|
||||||
|
@ -6310,7 +6310,7 @@ ConvertToPyObject(typval_T *tv)
|
|||||||
if (tv->vval.v_partial->pt_dict != NULL)
|
if (tv->vval.v_partial->pt_dict != NULL)
|
||||||
tv->vval.v_partial->pt_dict->dv_refcount++;
|
tv->vval.v_partial->pt_dict->dv_refcount++;
|
||||||
return NEW_FUNCTION(tv->vval.v_partial == NULL
|
return NEW_FUNCTION(tv->vval.v_partial == NULL
|
||||||
? (char_u *)"" : tv->vval.v_partial->pt_name,
|
? (char_u *)"" : partial_name(tv->vval.v_partial),
|
||||||
tv->vval.v_partial->pt_argc, argv,
|
tv->vval.v_partial->pt_argc, argv,
|
||||||
tv->vval.v_partial->pt_dict,
|
tv->vval.v_partial->pt_dict,
|
||||||
tv->vval.v_partial->pt_auto);
|
tv->vval.v_partial->pt_auto);
|
||||||
|
12
src/misc2.c
12
src/misc2.c
@ -1217,16 +1217,20 @@ free_all_mem(void)
|
|||||||
if (delete_first_msg() == FAIL)
|
if (delete_first_msg() == FAIL)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
# ifdef FEAT_EVAL
|
|
||||||
eval_clear();
|
|
||||||
# endif
|
|
||||||
# ifdef FEAT_JOB_CHANNEL
|
# ifdef FEAT_JOB_CHANNEL
|
||||||
channel_free_all();
|
channel_free_all();
|
||||||
job_free_all();
|
|
||||||
# endif
|
# endif
|
||||||
#ifdef FEAT_TIMERS
|
#ifdef FEAT_TIMERS
|
||||||
timer_free_all();
|
timer_free_all();
|
||||||
#endif
|
#endif
|
||||||
|
# ifdef FEAT_EVAL
|
||||||
|
/* must be after channel_free_all() with unrefs partials */
|
||||||
|
eval_clear();
|
||||||
|
# endif
|
||||||
|
# ifdef FEAT_JOB_CHANNEL
|
||||||
|
/* must be after eval_clear() with unrefs jobs */
|
||||||
|
job_free_all();
|
||||||
|
# endif
|
||||||
|
|
||||||
free_termoptions();
|
free_termoptions();
|
||||||
|
|
||||||
|
@ -40,6 +40,7 @@ char_u *get_user_var_name(expand_T *xp, int idx);
|
|||||||
int eval0(char_u *arg, typval_T *rettv, char_u **nextcmd, int evaluate);
|
int eval0(char_u *arg, typval_T *rettv, char_u **nextcmd, int evaluate);
|
||||||
int eval1(char_u **arg, typval_T *rettv, int evaluate);
|
int eval1(char_u **arg, typval_T *rettv, int evaluate);
|
||||||
int get_option_tv(char_u **arg, typval_T *rettv, int evaluate);
|
int get_option_tv(char_u **arg, typval_T *rettv, int evaluate);
|
||||||
|
char_u *partial_name(partial_T *pt);
|
||||||
void partial_unref(partial_T *pt);
|
void partial_unref(partial_T *pt);
|
||||||
int tv_equal(typval_T *tv1, typval_T *tv2, int ic, int recursive);
|
int tv_equal(typval_T *tv1, typval_T *tv2, int ic, int recursive);
|
||||||
int get_copyID(void);
|
int get_copyID(void);
|
||||||
|
@ -3,9 +3,11 @@ void func_init(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);
|
||||||
int get_func_tv(char_u *name, int len, typval_T *rettv, char_u **arg, linenr_T firstline, linenr_T lastline, int *doesrange, int evaluate, partial_T *partial, dict_T *selfdict);
|
int get_func_tv(char_u *name, int len, typval_T *rettv, char_u **arg, linenr_T firstline, linenr_T lastline, int *doesrange, int evaluate, partial_T *partial, dict_T *selfdict);
|
||||||
|
ufunc_T *find_func(char_u *name);
|
||||||
void free_all_functions(void);
|
void free_all_functions(void);
|
||||||
int func_call(char_u *name, typval_T *args, partial_T *partial, dict_T *selfdict, typval_T *rettv);
|
int func_call(char_u *name, typval_T *args, partial_T *partial, dict_T *selfdict, typval_T *rettv);
|
||||||
int call_func(char_u *funcname, int len, typval_T *rettv, int argcount_in, typval_T *argvars_in, int (*argv_func)(int, typval_T *, int), linenr_T firstline, linenr_T lastline, int *doesrange, int evaluate, partial_T *partial, dict_T *selfdict_in);
|
int call_func(char_u *funcname, int len, typval_T *rettv, int argcount_in, typval_T *argvars_in, int (*argv_func)(int, typval_T *, int), linenr_T firstline, linenr_T lastline, int *doesrange, int evaluate, partial_T *partial, dict_T *selfdict_in);
|
||||||
|
char_u *trans_function_name(char_u **pp, int skip, int flags, funcdict_T *fdp, partial_T **partial);
|
||||||
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 translated_function_exists(char_u *name);
|
||||||
@ -17,7 +19,9 @@ void prof_child_exit(proftime_T *tm);
|
|||||||
char_u *get_user_func_name(expand_T *xp, int idx);
|
char_u *get_user_func_name(expand_T *xp, int idx);
|
||||||
void ex_delfunction(exarg_T *eap);
|
void ex_delfunction(exarg_T *eap);
|
||||||
void func_unref(char_u *name);
|
void func_unref(char_u *name);
|
||||||
|
void func_ptr_unref(ufunc_T *fp);
|
||||||
void func_ref(char_u *name);
|
void func_ref(char_u *name);
|
||||||
|
void func_ptr_ref(ufunc_T *fp);
|
||||||
void ex_return(exarg_T *eap);
|
void ex_return(exarg_T *eap);
|
||||||
void ex_call(exarg_T *eap);
|
void ex_call(exarg_T *eap);
|
||||||
int do_return(exarg_T *eap, int reanimate, int is_cmd, void *rettv);
|
int do_return(exarg_T *eap, int reanimate, int is_cmd, void *rettv);
|
||||||
@ -51,5 +55,5 @@ dictitem_T *find_var_in_scoped_ht(char_u *name, char_u **varname, int no_autoloa
|
|||||||
int set_ref_in_previous_funccal(int copyID);
|
int set_ref_in_previous_funccal(int copyID);
|
||||||
int set_ref_in_call_stack(int copyID);
|
int set_ref_in_call_stack(int copyID);
|
||||||
int set_ref_in_func_args(int copyID);
|
int set_ref_in_func_args(int copyID);
|
||||||
int set_ref_in_func(char_u *name, int copyID);
|
int set_ref_in_func(char_u *name, ufunc_T *fp_in, int copyID);
|
||||||
/* vim: set ft=c : */
|
/* vim: set ft=c : */
|
||||||
|
@ -7499,7 +7499,7 @@ vim_regsub_both(
|
|||||||
{
|
{
|
||||||
partial_T *partial = expr->vval.v_partial;
|
partial_T *partial = expr->vval.v_partial;
|
||||||
|
|
||||||
s = partial->pt_name;
|
s = partial_name(partial);
|
||||||
call_func(s, (int)STRLEN(s), &rettv,
|
call_func(s, (int)STRLEN(s), &rettv,
|
||||||
1, argv, fill_submatch_list,
|
1, argv, fill_submatch_list,
|
||||||
0L, 0L, &dummy, TRUE, partial, NULL);
|
0L, 0L, &dummy, TRUE, partial, NULL);
|
||||||
|
@ -1295,10 +1295,100 @@ struct dictvar_S
|
|||||||
dict_T *dv_used_prev; /* previous dict in used dicts list */
|
dict_T *dv_used_prev; /* previous dict in used dicts list */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#if defined(FEAT_EVAL) || defined(PROTO)
|
||||||
|
typedef struct funccall_S funccall_T;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Structure to hold info for a user function.
|
||||||
|
*/
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
int uf_varargs; /* variable nr of arguments */
|
||||||
|
int uf_flags;
|
||||||
|
int uf_calls; /* nr of active calls */
|
||||||
|
garray_T uf_args; /* arguments */
|
||||||
|
garray_T uf_lines; /* function lines */
|
||||||
|
#ifdef FEAT_PROFILE
|
||||||
|
int uf_profiling; /* TRUE when func is being profiled */
|
||||||
|
/* profiling the function as a whole */
|
||||||
|
int uf_tm_count; /* nr of calls */
|
||||||
|
proftime_T uf_tm_total; /* time spent in function + children */
|
||||||
|
proftime_T uf_tm_self; /* time spent in function itself */
|
||||||
|
proftime_T uf_tm_children; /* time spent in children this call */
|
||||||
|
/* profiling the function per line */
|
||||||
|
int *uf_tml_count; /* nr of times line was executed */
|
||||||
|
proftime_T *uf_tml_total; /* time spent in a line + children */
|
||||||
|
proftime_T *uf_tml_self; /* time spent in a line itself */
|
||||||
|
proftime_T uf_tml_start; /* start time for current line */
|
||||||
|
proftime_T uf_tml_children; /* time spent in children for this line */
|
||||||
|
proftime_T uf_tml_wait; /* start wait time for current line */
|
||||||
|
int uf_tml_idx; /* index of line being timed; -1 if none */
|
||||||
|
int uf_tml_execed; /* line being timed was executed */
|
||||||
|
#endif
|
||||||
|
scid_T uf_script_ID; /* ID of script where function was defined,
|
||||||
|
used for s: variables */
|
||||||
|
int uf_refcount; /* for numbered function: reference count */
|
||||||
|
funccall_T *uf_scoped; /* l: local variables for closure */
|
||||||
|
char_u uf_name[1]; /* name of function (actually longer); can
|
||||||
|
start with <SNR>123_ (<SNR> is K_SPECIAL
|
||||||
|
KS_EXTRA KE_SNR) */
|
||||||
|
} ufunc_T;
|
||||||
|
|
||||||
|
#define MAX_FUNC_ARGS 20 /* maximum number of function arguments */
|
||||||
|
#define VAR_SHORT_LEN 20 /* short variable name length */
|
||||||
|
#define FIXVAR_CNT 12 /* number of fixed variables */
|
||||||
|
|
||||||
|
/* structure to hold info for a function that is currently being executed. */
|
||||||
|
struct funccall_S
|
||||||
|
{
|
||||||
|
ufunc_T *func; /* function being called */
|
||||||
|
int linenr; /* next line to be executed */
|
||||||
|
int returned; /* ":return" used */
|
||||||
|
struct /* fixed variables for arguments */
|
||||||
|
{
|
||||||
|
dictitem_T var; /* variable (without room for name) */
|
||||||
|
char_u room[VAR_SHORT_LEN]; /* room for the name */
|
||||||
|
} fixvar[FIXVAR_CNT];
|
||||||
|
dict_T l_vars; /* l: local function variables */
|
||||||
|
dictitem_T l_vars_var; /* variable for l: scope */
|
||||||
|
dict_T l_avars; /* a: argument variables */
|
||||||
|
dictitem_T l_avars_var; /* variable for a: scope */
|
||||||
|
list_T l_varlist; /* list for a:000 */
|
||||||
|
listitem_T l_listitems[MAX_FUNC_ARGS]; /* listitems for a:000 */
|
||||||
|
typval_T *rettv; /* return value */
|
||||||
|
linenr_T breakpoint; /* next line with breakpoint or zero */
|
||||||
|
int dbg_tick; /* debug_tick when breakpoint was set */
|
||||||
|
int level; /* top nesting level of executed function */
|
||||||
|
#ifdef FEAT_PROFILE
|
||||||
|
proftime_T prof_child; /* time spent in a child */
|
||||||
|
#endif
|
||||||
|
funccall_T *caller; /* calling function or NULL */
|
||||||
|
|
||||||
|
/* for closure */
|
||||||
|
int fc_refcount;
|
||||||
|
int fc_copyID; /* for garbage collection */
|
||||||
|
garray_T fc_funcs; /* list of ufunc_T* which refer this */
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Struct used by trans_function_name()
|
||||||
|
*/
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
dict_T *fd_dict; /* Dictionary used */
|
||||||
|
char_u *fd_newkey; /* new key in "dict" in allocated memory */
|
||||||
|
dictitem_T *fd_di; /* Dictionary item used */
|
||||||
|
} funcdict_T;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
struct partial_S
|
struct partial_S
|
||||||
{
|
{
|
||||||
int pt_refcount; /* reference count */
|
int pt_refcount; /* reference count */
|
||||||
char_u *pt_name; /* function name */
|
char_u *pt_name; /* function name; when NULL use
|
||||||
|
* pt_func->uf_name */
|
||||||
|
ufunc_T *pt_func; /* function pointer; when NULL lookup function
|
||||||
|
* with pt_name */
|
||||||
int pt_auto; /* when TRUE the partial was created for using
|
int pt_auto; /* when TRUE the partial was created for using
|
||||||
dict.member in handle_subscript() */
|
dict.member in handle_subscript() */
|
||||||
int pt_argc; /* number of arguments */
|
int pt_argc; /* number of arguments */
|
||||||
|
@ -179,3 +179,18 @@ func Test_function_with_funcref()
|
|||||||
call assert_equal(v:t_string, s:fref('x'))
|
call assert_equal(v:t_string, s:fref('x'))
|
||||||
call assert_fails("call function('s:f')", 'E700:')
|
call assert_fails("call function('s:f')", 'E700:')
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
|
func Test_funcref()
|
||||||
|
func! One()
|
||||||
|
return 1
|
||||||
|
endfunc
|
||||||
|
let OneByName = function('One')
|
||||||
|
let OneByRef = funcref('One')
|
||||||
|
func! One()
|
||||||
|
return 2
|
||||||
|
endfunc
|
||||||
|
call assert_equal(2, OneByName())
|
||||||
|
call assert_equal(1, OneByRef())
|
||||||
|
let OneByRef = funcref('One')
|
||||||
|
call assert_equal(2, OneByRef())
|
||||||
|
endfunc
|
||||||
|
@ -152,7 +152,7 @@ function! Test_lambda_delfunc()
|
|||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
let l:F = s:gen()
|
let l:F = s:gen()
|
||||||
call assert_fails(':call l:F()', 'E117:')
|
call assert_fails(':call l:F()', 'E933:')
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! Test_lambda_scope()
|
function! Test_lambda_scope()
|
||||||
|
346
src/userfunc.c
346
src/userfunc.c
@ -14,52 +14,12 @@
|
|||||||
#include "vim.h"
|
#include "vim.h"
|
||||||
|
|
||||||
#if defined(FEAT_EVAL) || defined(PROTO)
|
#if defined(FEAT_EVAL) || defined(PROTO)
|
||||||
|
|
||||||
typedef struct funccall_S funccall_T;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Structure to hold info for a user function.
|
|
||||||
*/
|
|
||||||
typedef struct ufunc ufunc_T;
|
|
||||||
|
|
||||||
struct ufunc
|
|
||||||
{
|
|
||||||
int uf_varargs; /* variable nr of arguments */
|
|
||||||
int uf_flags;
|
|
||||||
int uf_calls; /* nr of active calls */
|
|
||||||
garray_T uf_args; /* arguments */
|
|
||||||
garray_T uf_lines; /* function lines */
|
|
||||||
#ifdef FEAT_PROFILE
|
|
||||||
int uf_profiling; /* TRUE when func is being profiled */
|
|
||||||
/* profiling the function as a whole */
|
|
||||||
int uf_tm_count; /* nr of calls */
|
|
||||||
proftime_T uf_tm_total; /* time spent in function + children */
|
|
||||||
proftime_T uf_tm_self; /* time spent in function itself */
|
|
||||||
proftime_T uf_tm_children; /* time spent in children this call */
|
|
||||||
/* profiling the function per line */
|
|
||||||
int *uf_tml_count; /* nr of times line was executed */
|
|
||||||
proftime_T *uf_tml_total; /* time spent in a line + children */
|
|
||||||
proftime_T *uf_tml_self; /* time spent in a line itself */
|
|
||||||
proftime_T uf_tml_start; /* start time for current line */
|
|
||||||
proftime_T uf_tml_children; /* time spent in children for this line */
|
|
||||||
proftime_T uf_tml_wait; /* start wait time for current line */
|
|
||||||
int uf_tml_idx; /* index of line being timed; -1 if none */
|
|
||||||
int uf_tml_execed; /* line being timed was executed */
|
|
||||||
#endif
|
|
||||||
scid_T uf_script_ID; /* ID of script where function was defined,
|
|
||||||
used for s: variables */
|
|
||||||
int uf_refcount; /* for numbered function: reference count */
|
|
||||||
funccall_T *uf_scoped; /* l: local variables for closure */
|
|
||||||
char_u uf_name[1]; /* name of function (actually longer); can
|
|
||||||
start with <SNR>123_ (<SNR> is K_SPECIAL
|
|
||||||
KS_EXTRA KE_SNR) */
|
|
||||||
};
|
|
||||||
|
|
||||||
/* function flags */
|
/* function flags */
|
||||||
#define FC_ABORT 1 /* abort function on error */
|
#define FC_ABORT 1 /* abort function on error */
|
||||||
#define FC_RANGE 2 /* function accepts range */
|
#define FC_RANGE 2 /* function accepts range */
|
||||||
#define FC_DICT 4 /* Dict function, uses "self" */
|
#define FC_DICT 4 /* Dict function, uses "self" */
|
||||||
#define FC_CLOSURE 8 /* closure, uses outer scope variables */
|
#define FC_CLOSURE 8 /* closure, uses outer scope variables */
|
||||||
|
#define FC_DELETED 16 /* :delfunction used while uf_refcount > 0 */
|
||||||
|
|
||||||
/* From user function to hashitem and back. */
|
/* From user function to hashitem and back. */
|
||||||
#define UF2HIKEY(fp) ((fp)->uf_name)
|
#define UF2HIKEY(fp) ((fp)->uf_name)
|
||||||
@ -69,52 +29,6 @@ struct ufunc
|
|||||||
#define FUNCARG(fp, j) ((char_u **)(fp->uf_args.ga_data))[j]
|
#define FUNCARG(fp, j) ((char_u **)(fp->uf_args.ga_data))[j]
|
||||||
#define FUNCLINE(fp, j) ((char_u **)(fp->uf_lines.ga_data))[j]
|
#define FUNCLINE(fp, j) ((char_u **)(fp->uf_lines.ga_data))[j]
|
||||||
|
|
||||||
#define MAX_FUNC_ARGS 20 /* maximum number of function arguments */
|
|
||||||
#define VAR_SHORT_LEN 20 /* short variable name length */
|
|
||||||
#define FIXVAR_CNT 12 /* number of fixed variables */
|
|
||||||
|
|
||||||
/* structure to hold info for a function that is currently being executed. */
|
|
||||||
struct funccall_S
|
|
||||||
{
|
|
||||||
ufunc_T *func; /* function being called */
|
|
||||||
int linenr; /* next line to be executed */
|
|
||||||
int returned; /* ":return" used */
|
|
||||||
struct /* fixed variables for arguments */
|
|
||||||
{
|
|
||||||
dictitem_T var; /* variable (without room for name) */
|
|
||||||
char_u room[VAR_SHORT_LEN]; /* room for the name */
|
|
||||||
} fixvar[FIXVAR_CNT];
|
|
||||||
dict_T l_vars; /* l: local function variables */
|
|
||||||
dictitem_T l_vars_var; /* variable for l: scope */
|
|
||||||
dict_T l_avars; /* a: argument variables */
|
|
||||||
dictitem_T l_avars_var; /* variable for a: scope */
|
|
||||||
list_T l_varlist; /* list for a:000 */
|
|
||||||
listitem_T l_listitems[MAX_FUNC_ARGS]; /* listitems for a:000 */
|
|
||||||
typval_T *rettv; /* return value */
|
|
||||||
linenr_T breakpoint; /* next line with breakpoint or zero */
|
|
||||||
int dbg_tick; /* debug_tick when breakpoint was set */
|
|
||||||
int level; /* top nesting level of executed function */
|
|
||||||
#ifdef FEAT_PROFILE
|
|
||||||
proftime_T prof_child; /* time spent in a child */
|
|
||||||
#endif
|
|
||||||
funccall_T *caller; /* calling function or NULL */
|
|
||||||
|
|
||||||
/* for closure */
|
|
||||||
int fc_refcount;
|
|
||||||
int fc_copyID; /* for garbage collection */
|
|
||||||
garray_T fc_funcs; /* list of ufunc_T* which refer this */
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Struct used by trans_function_name()
|
|
||||||
*/
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
dict_T *fd_dict; /* Dictionary used */
|
|
||||||
char_u *fd_newkey; /* new key in "dict" in allocated memory */
|
|
||||||
dictitem_T *fd_di; /* Dictionary item used */
|
|
||||||
} funcdict_T;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* All user-defined functions are found in this hashtable.
|
* All user-defined functions are found in this hashtable.
|
||||||
*/
|
*/
|
||||||
@ -271,7 +185,7 @@ register_closure(ufunc_T *fp)
|
|||||||
return FAIL;
|
return FAIL;
|
||||||
((ufunc_T **)current_funccal->fc_funcs.ga_data)
|
((ufunc_T **)current_funccal->fc_funcs.ga_data)
|
||||||
[current_funccal->fc_funcs.ga_len++] = fp;
|
[current_funccal->fc_funcs.ga_len++] = fp;
|
||||||
func_ref(current_funccal->func->uf_name);
|
func_ptr_ref(current_funccal->func);
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -288,7 +202,6 @@ get_lambda_tv(char_u **arg, typval_T *rettv, int evaluate)
|
|||||||
ufunc_T *fp = NULL;
|
ufunc_T *fp = NULL;
|
||||||
int varargs;
|
int varargs;
|
||||||
int ret;
|
int ret;
|
||||||
char_u name[20];
|
|
||||||
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;
|
static int lambda_no = 0;
|
||||||
@ -331,14 +244,22 @@ get_lambda_tv(char_u **arg, typval_T *rettv, int evaluate)
|
|||||||
|
|
||||||
if (evaluate)
|
if (evaluate)
|
||||||
{
|
{
|
||||||
int len, flags = 0;
|
int len, flags = 0;
|
||||||
char_u *p;
|
char_u *p;
|
||||||
|
char_u name[20];
|
||||||
|
partial_T *pt;
|
||||||
|
|
||||||
sprintf((char*)name, "<lambda>%d", ++lambda_no);
|
sprintf((char*)name, "<lambda>%d", ++lambda_no);
|
||||||
|
|
||||||
fp = (ufunc_T *)alloc_clear((unsigned)(sizeof(ufunc_T) + STRLEN(name)));
|
fp = (ufunc_T *)alloc_clear((unsigned)(sizeof(ufunc_T) + STRLEN(name)));
|
||||||
if (fp == NULL)
|
if (fp == NULL)
|
||||||
goto errret;
|
goto errret;
|
||||||
|
pt = (partial_T *)alloc_clear((unsigned)sizeof(partial_T));
|
||||||
|
if (pt == NULL)
|
||||||
|
{
|
||||||
|
vim_free(fp);
|
||||||
|
goto errret;
|
||||||
|
}
|
||||||
|
|
||||||
ga_init2(&newlines, (int)sizeof(char_u *), 1);
|
ga_init2(&newlines, (int)sizeof(char_u *), 1);
|
||||||
if (ga_grow(&newlines, 1) == FAIL)
|
if (ga_grow(&newlines, 1) == FAIL)
|
||||||
@ -380,8 +301,10 @@ get_lambda_tv(char_u **arg, typval_T *rettv, int evaluate)
|
|||||||
fp->uf_calls = 0;
|
fp->uf_calls = 0;
|
||||||
fp->uf_script_ID = current_SID;
|
fp->uf_script_ID = current_SID;
|
||||||
|
|
||||||
rettv->vval.v_string = vim_strsave(name);
|
pt->pt_func = fp;
|
||||||
rettv->v_type = VAR_FUNC;
|
pt->pt_refcount = 1;
|
||||||
|
rettv->vval.v_partial = pt;
|
||||||
|
rettv->v_type = VAR_PARTIAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
eval_lavars_used = old_eval_lavars;
|
eval_lavars_used = old_eval_lavars;
|
||||||
@ -406,6 +329,7 @@ deref_func_name(char_u *name, int *lenp, partial_T **partialp, int no_autoload)
|
|||||||
{
|
{
|
||||||
dictitem_T *v;
|
dictitem_T *v;
|
||||||
int cc;
|
int cc;
|
||||||
|
char_u *s;
|
||||||
|
|
||||||
if (partialp != NULL)
|
if (partialp != NULL)
|
||||||
*partialp = NULL;
|
*partialp = NULL;
|
||||||
@ -421,8 +345,9 @@ deref_func_name(char_u *name, int *lenp, partial_T **partialp, int no_autoload)
|
|||||||
*lenp = 0;
|
*lenp = 0;
|
||||||
return (char_u *)""; /* just in case */
|
return (char_u *)""; /* just in case */
|
||||||
}
|
}
|
||||||
*lenp = (int)STRLEN(v->di_tv.vval.v_string);
|
s = v->di_tv.vval.v_string;
|
||||||
return v->di_tv.vval.v_string;
|
*lenp = (int)STRLEN(s);
|
||||||
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (v != NULL && v->di_tv.v_type == VAR_PARTIAL)
|
if (v != NULL && v->di_tv.v_type == VAR_PARTIAL)
|
||||||
@ -436,8 +361,9 @@ deref_func_name(char_u *name, int *lenp, partial_T **partialp, int no_autoload)
|
|||||||
}
|
}
|
||||||
if (partialp != NULL)
|
if (partialp != NULL)
|
||||||
*partialp = pt;
|
*partialp = pt;
|
||||||
*lenp = (int)STRLEN(pt->pt_name);
|
s = partial_name(pt);
|
||||||
return pt->pt_name;
|
*lenp = (int)STRLEN(s);
|
||||||
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
return name;
|
return name;
|
||||||
@ -611,7 +537,7 @@ fname_trans_sid(char_u *name, char_u *fname_buf, char_u **tofree, int *error)
|
|||||||
* Find a function by name, return pointer to it in ufuncs.
|
* Find a function by name, return pointer to it in ufuncs.
|
||||||
* Return NULL for unknown function.
|
* Return NULL for unknown function.
|
||||||
*/
|
*/
|
||||||
static ufunc_T *
|
ufunc_T *
|
||||||
find_func(char_u *name)
|
find_func(char_u *name)
|
||||||
{
|
{
|
||||||
hashitem_T *hi;
|
hashitem_T *hi;
|
||||||
@ -678,7 +604,7 @@ free_funccal(
|
|||||||
* funccall_T, don't clear it then. */
|
* funccall_T, don't clear it then. */
|
||||||
if (fp->uf_scoped == fc)
|
if (fp->uf_scoped == fc)
|
||||||
fp->uf_scoped = NULL;
|
fp->uf_scoped = NULL;
|
||||||
func_unref(fc->func->uf_name);
|
func_ptr_unref(fc->func);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ga_clear(&fc->fc_funcs);
|
ga_clear(&fc->fc_funcs);
|
||||||
@ -695,7 +621,7 @@ free_funccal(
|
|||||||
for (li = fc->l_varlist.lv_first; li != NULL; li = li->li_next)
|
for (li = fc->l_varlist.lv_first; li != NULL; li = li->li_next)
|
||||||
clear_tv(&li->li_tv);
|
clear_tv(&li->li_tv);
|
||||||
|
|
||||||
func_unref(fc->func->uf_name);
|
func_ptr_unref(fc->func);
|
||||||
vim_free(fc);
|
vim_free(fc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -759,7 +685,7 @@ call_user_func(
|
|||||||
fc->fc_refcount = 0;
|
fc->fc_refcount = 0;
|
||||||
fc->fc_copyID = 0;
|
fc->fc_copyID = 0;
|
||||||
ga_init2(&fc->fc_funcs, sizeof(ufunc_T *), 1);
|
ga_init2(&fc->fc_funcs, sizeof(ufunc_T *), 1);
|
||||||
func_ref(fp->uf_name);
|
func_ptr_ref(fp);
|
||||||
|
|
||||||
if (STRNCMP(fp->uf_name, "<lambda>", 8) == 0)
|
if (STRNCMP(fp->uf_name, "<lambda>", 8) == 0)
|
||||||
islambda = TRUE;
|
islambda = TRUE;
|
||||||
@ -1112,24 +1038,25 @@ funccal_unref(funccall_T *fc, ufunc_T *fp)
|
|||||||
|
|
||||||
if (--fc->fc_refcount <= 0)
|
if (--fc->fc_refcount <= 0)
|
||||||
{
|
{
|
||||||
for (pfc = &previous_funccal; *pfc != NULL; )
|
for (pfc = &previous_funccal; *pfc != NULL; pfc = &(*pfc)->caller)
|
||||||
{
|
{
|
||||||
if (fc == *pfc
|
if (fc == *pfc)
|
||||||
&& fc->l_varlist.lv_refcount == DO_NOT_FREE_CNT
|
{
|
||||||
|
if (fc->l_varlist.lv_refcount == DO_NOT_FREE_CNT
|
||||||
&& fc->l_vars.dv_refcount == DO_NOT_FREE_CNT
|
&& fc->l_vars.dv_refcount == DO_NOT_FREE_CNT
|
||||||
&& fc->l_avars.dv_refcount == DO_NOT_FREE_CNT)
|
&& fc->l_avars.dv_refcount == DO_NOT_FREE_CNT)
|
||||||
{
|
{
|
||||||
*pfc = fc->caller;
|
*pfc = fc->caller;
|
||||||
free_funccal(fc, TRUE);
|
free_funccal(fc, TRUE);
|
||||||
freed = TRUE;
|
freed = TRUE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
pfc = &(*pfc)->caller;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!freed)
|
if (!freed)
|
||||||
{
|
{
|
||||||
func_unref(fc->func->uf_name);
|
func_ptr_unref(fc->func);
|
||||||
|
|
||||||
if (fp != NULL)
|
if (fp != NULL)
|
||||||
for (i = 0; i < fc->fc_funcs.ga_len; ++i)
|
for (i = 0; i < fc->fc_funcs.ga_len; ++i)
|
||||||
@ -1140,14 +1067,25 @@ funccal_unref(funccall_T *fc, ufunc_T *fp)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Remove the function from the function hashtable. If the function was
|
||||||
|
* deleted while it still has references this was already done.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
func_remove(ufunc_T *fp)
|
||||||
|
{
|
||||||
|
hashitem_T *hi = hash_find(&func_hashtab, UF2HIKEY(fp));
|
||||||
|
|
||||||
|
if (!HASHITEM_EMPTY(hi))
|
||||||
|
hash_remove(&func_hashtab, hi);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Free a function and remove it from the list of functions.
|
* Free a function and remove it from the list of functions.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
func_free(ufunc_T *fp)
|
func_free(ufunc_T *fp)
|
||||||
{
|
{
|
||||||
hashitem_T *hi;
|
|
||||||
|
|
||||||
/* clear this function */
|
/* clear this function */
|
||||||
ga_clear_strings(&(fp->uf_args));
|
ga_clear_strings(&(fp->uf_args));
|
||||||
ga_clear_strings(&(fp->uf_lines));
|
ga_clear_strings(&(fp->uf_lines));
|
||||||
@ -1156,13 +1094,7 @@ func_free(ufunc_T *fp)
|
|||||||
vim_free(fp->uf_tml_total);
|
vim_free(fp->uf_tml_total);
|
||||||
vim_free(fp->uf_tml_self);
|
vim_free(fp->uf_tml_self);
|
||||||
#endif
|
#endif
|
||||||
|
func_remove(fp);
|
||||||
/* remove the function from the function hashtable */
|
|
||||||
hi = hash_find(&func_hashtab, UF2HIKEY(fp));
|
|
||||||
if (HASHITEM_EMPTY(hi))
|
|
||||||
EMSG2(_(e_intern2), "func_free()");
|
|
||||||
else
|
|
||||||
hash_remove(&func_hashtab, hi);
|
|
||||||
|
|
||||||
funccal_unref(fp->uf_scoped, fp);
|
funccal_unref(fp->uf_scoped, fp);
|
||||||
|
|
||||||
@ -1333,7 +1265,10 @@ call_func(
|
|||||||
/*
|
/*
|
||||||
* User defined function.
|
* User defined function.
|
||||||
*/
|
*/
|
||||||
fp = find_func(rfname);
|
if (partial != NULL && partial->pt_func != NULL)
|
||||||
|
fp = partial->pt_func;
|
||||||
|
else
|
||||||
|
fp = find_func(rfname);
|
||||||
|
|
||||||
#ifdef FEAT_AUTOCMD
|
#ifdef FEAT_AUTOCMD
|
||||||
/* Trigger FuncUndefined event, may load the function. */
|
/* Trigger FuncUndefined event, may load the function. */
|
||||||
@ -1353,7 +1288,9 @@ call_func(
|
|||||||
fp = find_func(rfname);
|
fp = find_func(rfname);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fp != NULL)
|
if (fp != NULL && (fp->uf_flags & FC_DELETED))
|
||||||
|
error = ERROR_DELETED;
|
||||||
|
else if (fp != NULL)
|
||||||
{
|
{
|
||||||
if (argv_func != NULL)
|
if (argv_func != NULL)
|
||||||
argcount = argv_func(argcount, argvars, fp->uf_args.ga_len);
|
argcount = argv_func(argcount, argvars, fp->uf_args.ga_len);
|
||||||
@ -1387,9 +1324,7 @@ call_func(
|
|||||||
call_user_func(fp, argcount, argvars, rettv,
|
call_user_func(fp, argcount, argvars, rettv,
|
||||||
firstline, lastline,
|
firstline, lastline,
|
||||||
(fp->uf_flags & FC_DICT) ? selfdict : NULL);
|
(fp->uf_flags & FC_DICT) ? selfdict : NULL);
|
||||||
if (--fp->uf_calls <= 0 && (isdigit(*fp->uf_name)
|
if (--fp->uf_calls <= 0 && fp->uf_refcount <= 0)
|
||||||
|| STRNCMP(fp->uf_name, "<lambda>", 8) == 0)
|
|
||||||
&& fp->uf_refcount <= 0)
|
|
||||||
/* Function was unreferenced while being used, free it
|
/* Function was unreferenced while being used, free it
|
||||||
* now. */
|
* now. */
|
||||||
func_free(fp);
|
func_free(fp);
|
||||||
@ -1433,6 +1368,9 @@ call_func(
|
|||||||
case ERROR_UNKNOWN:
|
case ERROR_UNKNOWN:
|
||||||
emsg_funcname(N_("E117: Unknown function: %s"), name);
|
emsg_funcname(N_("E117: Unknown function: %s"), name);
|
||||||
break;
|
break;
|
||||||
|
case ERROR_DELETED:
|
||||||
|
emsg_funcname(N_("E933: Function was deleted: %s"), name);
|
||||||
|
break;
|
||||||
case ERROR_TOOMANY:
|
case ERROR_TOOMANY:
|
||||||
emsg_funcname((char *)e_toomanyarg, name);
|
emsg_funcname((char *)e_toomanyarg, name);
|
||||||
break;
|
break;
|
||||||
@ -1516,7 +1454,7 @@ list_func_head(ufunc_T *fp, int indent)
|
|||||||
* TFN_NO_DEREF: do not dereference a Funcref
|
* TFN_NO_DEREF: do not dereference a Funcref
|
||||||
* Advances "pp" to just after the function name (if no error).
|
* Advances "pp" to just after the function name (if no error).
|
||||||
*/
|
*/
|
||||||
static char_u *
|
char_u *
|
||||||
trans_function_name(
|
trans_function_name(
|
||||||
char_u **pp,
|
char_u **pp,
|
||||||
int skip, /* only find the end, don't evaluate */
|
int skip, /* only find the end, don't evaluate */
|
||||||
@ -1595,7 +1533,7 @@ trans_function_name(
|
|||||||
else if (lv.ll_tv->v_type == VAR_PARTIAL
|
else if (lv.ll_tv->v_type == VAR_PARTIAL
|
||||||
&& lv.ll_tv->vval.v_partial != NULL)
|
&& lv.ll_tv->vval.v_partial != NULL)
|
||||||
{
|
{
|
||||||
name = vim_strsave(lv.ll_tv->vval.v_partial->pt_name);
|
name = vim_strsave(partial_name(lv.ll_tv->vval.v_partial));
|
||||||
*pp = end;
|
*pp = end;
|
||||||
if (partial != NULL)
|
if (partial != NULL)
|
||||||
*partial = lv.ll_tv->vval.v_partial;
|
*partial = lv.ll_tv->vval.v_partial;
|
||||||
@ -1752,6 +1690,7 @@ ex_function(exarg_T *eap)
|
|||||||
int varargs = FALSE;
|
int varargs = FALSE;
|
||||||
int flags = 0;
|
int flags = 0;
|
||||||
ufunc_T *fp;
|
ufunc_T *fp;
|
||||||
|
int overwrite = FALSE;
|
||||||
int indent;
|
int indent;
|
||||||
int nesting;
|
int nesting;
|
||||||
char_u *skip_until = NULL;
|
char_u *skip_until = NULL;
|
||||||
@ -2214,11 +2153,22 @@ ex_function(exarg_T *eap)
|
|||||||
name);
|
name);
|
||||||
goto erret;
|
goto erret;
|
||||||
}
|
}
|
||||||
/* redefine existing function */
|
if (fp->uf_refcount > 1)
|
||||||
ga_clear_strings(&(fp->uf_args));
|
{
|
||||||
ga_clear_strings(&(fp->uf_lines));
|
/* This function is referenced somewhere, don't redefine it but
|
||||||
vim_free(name);
|
* create a new one. */
|
||||||
name = NULL;
|
--fp->uf_refcount;
|
||||||
|
fp = NULL;
|
||||||
|
overwrite = TRUE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* redefine existing function */
|
||||||
|
ga_clear_strings(&(fp->uf_args));
|
||||||
|
ga_clear_strings(&(fp->uf_lines));
|
||||||
|
vim_free(name);
|
||||||
|
name = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -2308,7 +2258,6 @@ ex_function(exarg_T *eap)
|
|||||||
fudi.fd_di->di_tv.v_type = VAR_FUNC;
|
fudi.fd_di->di_tv.v_type = VAR_FUNC;
|
||||||
fudi.fd_di->di_tv.v_lock = 0;
|
fudi.fd_di->di_tv.v_lock = 0;
|
||||||
fudi.fd_di->di_tv.vval.v_string = vim_strsave(name);
|
fudi.fd_di->di_tv.vval.v_string = vim_strsave(name);
|
||||||
fp->uf_refcount = 1;
|
|
||||||
|
|
||||||
/* behave like "dict" was used */
|
/* behave like "dict" was used */
|
||||||
flags |= FC_DICT;
|
flags |= FC_DICT;
|
||||||
@ -2316,17 +2265,22 @@ ex_function(exarg_T *eap)
|
|||||||
|
|
||||||
/* insert the new function in the function list */
|
/* insert the new function in the function list */
|
||||||
STRCPY(fp->uf_name, name);
|
STRCPY(fp->uf_name, name);
|
||||||
if (hash_add(&func_hashtab, UF2HIKEY(fp)) == FAIL)
|
if (overwrite)
|
||||||
|
{
|
||||||
|
hi = hash_find(&func_hashtab, name);
|
||||||
|
hi->hi_key = UF2HIKEY(fp);
|
||||||
|
}
|
||||||
|
else if (hash_add(&func_hashtab, UF2HIKEY(fp)) == FAIL)
|
||||||
{
|
{
|
||||||
vim_free(fp);
|
vim_free(fp);
|
||||||
goto erret;
|
goto erret;
|
||||||
}
|
}
|
||||||
|
fp->uf_refcount = 1;
|
||||||
}
|
}
|
||||||
fp->uf_args = newargs;
|
fp->uf_args = newargs;
|
||||||
fp->uf_lines = newlines;
|
fp->uf_lines = newlines;
|
||||||
if ((flags & FC_CLOSURE) != 0)
|
if ((flags & FC_CLOSURE) != 0)
|
||||||
{
|
{
|
||||||
++fp->uf_refcount;
|
|
||||||
if (register_closure(fp) == FAIL)
|
if (register_closure(fp) == FAIL)
|
||||||
goto erret;
|
goto erret;
|
||||||
}
|
}
|
||||||
@ -2750,13 +2704,30 @@ ex_delfunction(exarg_T *eap)
|
|||||||
dictitem_remove(fudi.fd_dict, fudi.fd_di);
|
dictitem_remove(fudi.fd_dict, fudi.fd_di);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
func_free(fp);
|
{
|
||||||
|
/* Normal functions (not numbered functions and lambdas) have a
|
||||||
|
* refcount of 1 for the entry in the hashtable. When deleting
|
||||||
|
* them and the refcount is more than one, it should be kept.
|
||||||
|
* Numbered functions and lambdas snould be kept if the refcount is
|
||||||
|
* one or more. */
|
||||||
|
if (fp->uf_refcount > (isdigit(fp->uf_name[0])
|
||||||
|
|| fp->uf_name[0] == '<') ? 0 : 1)
|
||||||
|
{
|
||||||
|
/* Function is still referenced somewhere. Don't free it but
|
||||||
|
* do remove it from the hashtable. */
|
||||||
|
func_remove(fp);
|
||||||
|
fp->uf_flags |= FC_DELETED;
|
||||||
|
fp->uf_refcount--;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
func_free(fp);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Unreference a Function: decrement the reference count and free it when it
|
* Unreference a Function: decrement the reference count and free it when it
|
||||||
* becomes zero. Only for numbered functions.
|
* becomes zero.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
func_unref(char_u *name)
|
func_unref(char_u *name)
|
||||||
@ -2765,22 +2736,30 @@ func_unref(char_u *name)
|
|||||||
|
|
||||||
if (name == NULL)
|
if (name == NULL)
|
||||||
return;
|
return;
|
||||||
if (isdigit(*name))
|
fp = find_func(name);
|
||||||
|
if (fp == NULL && isdigit(*name))
|
||||||
{
|
{
|
||||||
fp = find_func(name);
|
|
||||||
if (fp == NULL)
|
|
||||||
{
|
|
||||||
#ifdef EXITFREE
|
#ifdef EXITFREE
|
||||||
if (!entered_free_all_mem)
|
if (!entered_free_all_mem)
|
||||||
#endif
|
#endif
|
||||||
EMSG2(_(e_intern2), "func_unref()");
|
EMSG2(_(e_intern2), "func_unref()");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (STRNCMP(name, "<lambda>", 8) == 0)
|
if (fp != NULL && --fp->uf_refcount <= 0)
|
||||||
{
|
{
|
||||||
/* fail silently, when lambda function isn't found. */
|
/* Only delete it when it's not being used. Otherwise it's done
|
||||||
fp = find_func(name);
|
* when "uf_calls" becomes zero. */
|
||||||
|
if (fp->uf_calls == 0)
|
||||||
|
func_free(fp);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Unreference a Function: decrement the reference count and free it when it
|
||||||
|
* becomes zero.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
func_ptr_unref(ufunc_T *fp)
|
||||||
|
{
|
||||||
if (fp != NULL && --fp->uf_refcount <= 0)
|
if (fp != NULL && --fp->uf_refcount <= 0)
|
||||||
{
|
{
|
||||||
/* Only delete it when it's not being used. Otherwise it's done
|
/* Only delete it when it's not being used. Otherwise it's done
|
||||||
@ -2800,21 +2779,23 @@ func_ref(char_u *name)
|
|||||||
|
|
||||||
if (name == NULL)
|
if (name == NULL)
|
||||||
return;
|
return;
|
||||||
|
fp = find_func(name);
|
||||||
|
if (fp != NULL)
|
||||||
|
++fp->uf_refcount;
|
||||||
else if (isdigit(*name))
|
else if (isdigit(*name))
|
||||||
{
|
/* Only give an error for a numbered function.
|
||||||
fp = find_func(name);
|
* Fail silently, when named or lambda function isn't found. */
|
||||||
if (fp == NULL)
|
EMSG2(_(e_intern2), "func_ref()");
|
||||||
EMSG2(_(e_intern2), "func_ref()");
|
}
|
||||||
else
|
|
||||||
++fp->uf_refcount;
|
/*
|
||||||
}
|
* Count a reference to a Function.
|
||||||
else if (STRNCMP(name, "<lambda>", 8) == 0)
|
*/
|
||||||
{
|
void
|
||||||
/* fail silently, when lambda function isn't found. */
|
func_ptr_ref(ufunc_T *fp)
|
||||||
fp = find_func(name);
|
{
|
||||||
if (fp != NULL)
|
if (fp != NULL)
|
||||||
++fp->uf_refcount;
|
++fp->uf_refcount;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -3298,18 +3279,24 @@ func_has_abort(
|
|||||||
dict_T *
|
dict_T *
|
||||||
make_partial(dict_T *selfdict_in, typval_T *rettv)
|
make_partial(dict_T *selfdict_in, typval_T *rettv)
|
||||||
{
|
{
|
||||||
char_u *fname = rettv->v_type == VAR_FUNC ? rettv->vval.v_string
|
char_u *fname;
|
||||||
: rettv->vval.v_partial->pt_name;
|
|
||||||
char_u *tofree = NULL;
|
char_u *tofree = NULL;
|
||||||
ufunc_T *fp;
|
ufunc_T *fp;
|
||||||
char_u fname_buf[FLEN_FIXED + 1];
|
char_u fname_buf[FLEN_FIXED + 1];
|
||||||
int error;
|
int error;
|
||||||
dict_T *selfdict = selfdict_in;
|
dict_T *selfdict = selfdict_in;
|
||||||
|
|
||||||
/* Translate "s:func" to the stored function name. */
|
if (rettv->v_type == VAR_PARTIAL && rettv->vval.v_partial->pt_func != NULL)
|
||||||
fname = fname_trans_sid(fname, fname_buf, &tofree, &error);
|
fp = rettv->vval.v_partial->pt_func;
|
||||||
fp = find_func(fname);
|
else
|
||||||
vim_free(tofree);
|
{
|
||||||
|
fname = rettv->v_type == VAR_FUNC ? rettv->vval.v_string
|
||||||
|
: rettv->vval.v_partial->pt_name;
|
||||||
|
/* Translate "s:func" to the stored function name. */
|
||||||
|
fname = fname_trans_sid(fname, fname_buf, &tofree, &error);
|
||||||
|
fp = find_func(fname);
|
||||||
|
vim_free(tofree);
|
||||||
|
}
|
||||||
|
|
||||||
if (fp != NULL && (fp->uf_flags & FC_DICT))
|
if (fp != NULL && (fp->uf_flags & FC_DICT))
|
||||||
{
|
{
|
||||||
@ -3335,8 +3322,16 @@ make_partial(dict_T *selfdict_in, typval_T *rettv)
|
|||||||
/* Partial: copy the function name, use selfdict and copy
|
/* Partial: copy the function name, use selfdict and copy
|
||||||
* args. Can't take over name or args, the partial might
|
* args. Can't take over name or args, the partial might
|
||||||
* be referenced elsewhere. */
|
* be referenced elsewhere. */
|
||||||
pt->pt_name = vim_strsave(ret_pt->pt_name);
|
if (ret_pt->pt_name != NULL)
|
||||||
func_ref(pt->pt_name);
|
{
|
||||||
|
pt->pt_name = vim_strsave(ret_pt->pt_name);
|
||||||
|
func_ref(pt->pt_name);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pt->pt_func = ret_pt->pt_func;
|
||||||
|
func_ptr_ref(pt->pt_func);
|
||||||
|
}
|
||||||
if (ret_pt->pt_argc > 0)
|
if (ret_pt->pt_argc > 0)
|
||||||
{
|
{
|
||||||
pt->pt_argv = (typval_T *)alloc(
|
pt->pt_argv = (typval_T *)alloc(
|
||||||
@ -3703,20 +3698,23 @@ set_ref_in_func_args(int copyID)
|
|||||||
* Returns TRUE if setting references failed somehow.
|
* Returns TRUE if setting references failed somehow.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
set_ref_in_func(char_u *name, int copyID)
|
set_ref_in_func(char_u *name, ufunc_T *fp_in, int copyID)
|
||||||
{
|
{
|
||||||
ufunc_T *fp;
|
ufunc_T *fp = fp_in;
|
||||||
funccall_T *fc;
|
funccall_T *fc;
|
||||||
int error = ERROR_NONE;
|
int error = ERROR_NONE;
|
||||||
char_u fname_buf[FLEN_FIXED + 1];
|
char_u fname_buf[FLEN_FIXED + 1];
|
||||||
char_u *tofree = NULL;
|
char_u *tofree = NULL;
|
||||||
char_u *fname;
|
char_u *fname;
|
||||||
|
|
||||||
if (name == NULL)
|
if (name == NULL && fp_in == NULL)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
fname = fname_trans_sid(name, fname_buf, &tofree, &error);
|
if (fp_in == NULL)
|
||||||
fp = find_func(fname);
|
{
|
||||||
|
fname = fname_trans_sid(name, fname_buf, &tofree, &error);
|
||||||
|
fp = find_func(fname);
|
||||||
|
}
|
||||||
if (fp != NULL)
|
if (fp != NULL)
|
||||||
{
|
{
|
||||||
for (fc = fp->uf_scoped; fc != NULL; fc = fc->func->uf_scoped)
|
for (fc = fp->uf_scoped; fc != NULL; fc = fc->func->uf_scoped)
|
||||||
|
@ -763,6 +763,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 */
|
||||||
|
/**/
|
||||||
|
2137,
|
||||||
/**/
|
/**/
|
||||||
2136,
|
2136,
|
||||||
/**/
|
/**/
|
||||||
|
@ -2475,6 +2475,7 @@ int vim_main2(int argc, char **argv);
|
|||||||
#define ERROR_DICT 4
|
#define ERROR_DICT 4
|
||||||
#define ERROR_NONE 5
|
#define ERROR_NONE 5
|
||||||
#define ERROR_OTHER 6
|
#define ERROR_OTHER 6
|
||||||
|
#define ERROR_DELETED 7
|
||||||
|
|
||||||
/* flags for find_name_end() */
|
/* flags for find_name_end() */
|
||||||
#define FNE_INCL_BR 1 /* include [] in name */
|
#define FNE_INCL_BR 1 /* include [] in name */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user