summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2016-08-01 15:40:54 +0200
committerBram Moolenaar <Bram@vim.org>2016-08-01 15:40:54 +0200
commit437bafe4c8a83ed71ee006eda7f54b65a90f0d4c (patch)
treedac9426b1bafe44f050bbb13c027de31117c089d
parent580164481924ed8611eb79f0247a0eb1ca0b3b9a (diff)
patch 7.4.2137v7.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.
-rw-r--r--runtime/doc/eval.txt29
-rw-r--r--src/channel.c25
-rw-r--r--src/eval.c34
-rw-r--r--src/evalfunc.c107
-rw-r--r--src/if_mzsch.c2
-rw-r--r--src/if_py_both.h2
-rw-r--r--src/misc2.c12
-rw-r--r--src/proto/eval.pro1
-rw-r--r--src/proto/userfunc.pro6
-rw-r--r--src/regexp.c2
-rw-r--r--src/structs.h92
-rw-r--r--src/testdir/test_expr.vim15
-rw-r--r--src/testdir/test_lambda.vim2
-rw-r--r--src/userfunc.c346
-rw-r--r--src/version.c2
-rw-r--r--src/vim.h1
16 files changed, 447 insertions, 231 deletions
diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt
index 8dfbb3a28e..7e0b73c612 100644
--- a/runtime/doc/eval.txt
+++ b/runtime/doc/eval.txt
@@ -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
@@ -1240,7 +1240,9 @@ function returns: >
:let Bar = Foo(4)
:echo Bar(6)
< 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()|: >
: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
foldtextresult({lnum}) String text for closed fold at {lnum}
foreground() Number bring the Vim window to the foreground
-function({name} [, {arglist}] [, {dict}])
+funcref({name} [, {arglist}] [, {dict}])
Funcref reference to function {name}
+function({name} [, {arglist}] [, {dict}])
+ Funcref named reference to function {name}
garbagecollect([{atexit}]) none free memory, breaking cyclic references
get({list}, {idx} [, {def}]) any get item {idx} from {list} 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
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({name} [, {arglist}] [, {dict}])
@@ -3857,12 +3870,16 @@ function({name} [, {arglist}] [, {dict}])
{name} can be the name of a user defined function or an
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}
argument is not allowed. E.g.: >
let FuncWithArg = function(dict.Func, [arg])
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.
That means the argument list and/or the dictionary is stored in
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
cursor. The top line has number one.
This function is mainly used for testing.
+ Alternatively you can use |winline()|.
Note: Same restrictions as with |screencol()|.
@@ -8039,6 +8057,7 @@ insert_expand Compiled with support for CTRL-X expansion commands in
Insert mode.
jumplist Compiled with |jumplist| support.
keymap Compiled with 'keymap' support.
+lambda Compiled with |lambda| support.
langmap Compiled with 'langmap' support.
libcall Compiled with |libcall()| support.
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
by its own, without other commands.
- *:delf* *:delfunction* *E130* *E131*
+ *:delf* *:delfunction* *E130* *E131* *E933*
:delf[unction] {name} Delete function {name}.
{name} can also be a |Dictionary| entry that is a
|Funcref|: >
diff --git a/src/channel.c b/src/channel.c
index 3b8b5afa05..5ee05e3332 100644
--- a/src/channel.c
+++ b/src/channel.c
@@ -1124,15 +1124,18 @@ set_callback(
if (callback != NULL && *callback != NUL)
{
if (partial != NULL)
- *cbp = partial->pt_name;
+ *cbp = partial_name(partial);
else
+ {
*cbp = vim_strsave(callback);
+ func_ref(*cbp);
+ }
}
else
*cbp = NULL;
*pp = partial;
- if (*pp != NULL)
- ++(*pp)->pt_refcount;
+ if (partial != NULL)
+ ++partial->pt_refcount;
}
/*
@@ -1279,7 +1282,10 @@ channel_set_req_callback(
item->cq_callback = callback;
}
else
+ {
item->cq_callback = vim_strsave(callback);
+ func_ref(item->cq_callback);
+ }
item->cq_seq_nr = id;
item->cq_prev = head->cq_prev;
head->cq_prev = item;
@@ -3923,14 +3929,24 @@ free_job_options(jobopt_T *opt)
{
if (opt->jo_partial != NULL)
partial_unref(opt->jo_partial);
+ else if (opt->jo_callback != NULL)
+ func_unref(opt->jo_callback);
if (opt->jo_out_partial != NULL)
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)
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)
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)
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;
}
else
+ {
job->jv_exit_cb = vim_strsave(opt->jo_exit_cb);
+ func_ref(job->jv_exit_cb);
+ }
}
}
}
diff --git a/src/eval.c b/src/eval.c
index cf2c771438..495bbb0697 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -5011,6 +5011,17 @@ get_lit_string_tv(char_u **arg, typval_T *rettv, int evaluate)
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
partial_free(partial_T *pt)
{
@@ -5020,8 +5031,13 @@ partial_free(partial_T *pt)
clear_tv(&pt->pt_argv[i]);
vim_free(pt->pt_argv);
dict_unref(pt->pt_dict);
- func_unref(pt->pt_name);
- vim_free(pt->pt_name);
+ if (pt->pt_name != NULL)
+ {
+ func_unref(pt->pt_name);
+ vim_free(pt->pt_name);
+ }
+ else
+ func_ptr_unref(pt->pt_func);
vim_free(pt);
}
@@ -5051,11 +5067,11 @@ func_equal(
/* empty and NULL function name considered the same */
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)
s1 = NULL;
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)
s2 = NULL;
if (s1 == NULL || s2 == NULL)
@@ -5550,7 +5566,7 @@ set_ref_in_item(
}
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)
{
@@ -5561,7 +5577,7 @@ set_ref_in_item(
*/
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)
{
@@ -5735,7 +5751,7 @@ echo_string_core(
{
partial_T *pt = tv->vval.v_partial;
char_u *fname = string_quote(pt == NULL ? NULL
- : pt->pt_name, FALSE);
+ : partial_name(pt), FALSE);
garray_T ga;
int i;
char_u *tf;
@@ -6871,7 +6887,7 @@ handle_subscript(
if (functv.v_type == VAR_PARTIAL)
{
pt = functv.vval.v_partial;
- s = pt->pt_name;
+ s = partial_name(pt);
}
else
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;
- s = partial->pt_name;
+ s = partial_name(partial);
if (call_func(s, (int)STRLEN(s), &rettv, 2, argv, NULL,
0L, 0L, &dummy, TRUE, partial, NULL) == FAIL)
goto theend;
diff --git a/src/evalfunc.c b/src/evalfunc.c
index 13864ea3a7..68a8b16414 100644
--- a/src/evalfunc.c
+++ b/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_foldtextresult(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_garbagecollect(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},
{"foldtextresult", 1, 1, f_foldtextresult},
{"foreground", 0, 0, f_foreground},
+ {"funcref", 1, 3, f_funcref},
{"function", 1, 3, f_function},
{"garbagecollect", 0, 1, f_garbagecollect},
{"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)
{
partial = argvars[0].vval.v_partial;
- func = partial->pt_name;
+ func = partial_name(partial);
}
else
func = get_tv_string(&argvars[0]);
@@ -3543,16 +3545,14 @@ f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
#endif
}
-/*
- * "function()" function
- */
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 *name;
int use_string = FALSE;
partial_T *arg_pt = NULL;
+ char_u *trans_name = NULL;
if (argvars[0].v_type == VAR_FUNC)
{
@@ -3564,7 +3564,7 @@ f_function(typval_T *argvars, typval_T *rettv)
{
/* function(dict.MyFunc, [arg]) */
arg_pt = argvars[0].vval.v_partial;
- s = arg_pt->pt_name;
+ s = partial_name(arg_pt);
}
else
{
@@ -3573,11 +3573,22 @@ f_function(typval_T *argvars, typval_T *rettv)
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)))
EMSG2(_(e_invarg2), s);
/* Don't check an autoload name for existence here. */
- else if (use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL
- && !function_exists(s, TRUE))
+ else if (trans_name != NULL && (is_funcref
+ ? find_func(trans_name) == NULL
+ : !translated_function_exists(trans_name)))
EMSG2(_("E700: Unknown function: %s"), s);
else
{
@@ -3625,7 +3636,7 @@ f_function(typval_T *argvars, typval_T *rettv)
{
EMSG(_("E922: expected a dict"));
vim_free(name);
- return;
+ goto theend;
}
if (argvars[dict_idx].vval.v_dict == NULL)
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"));
vim_free(name);
- return;
+ goto theend;
}
list = argvars[arg_idx].vval.v_list;
if (list == NULL || list->lv_len == 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));
@@ -3670,17 +3681,14 @@ f_function(typval_T *argvars, typval_T *rettv)
{
vim_free(pt);
vim_free(name);
- return;
- }
- 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++]);
+ goto theend;
}
+ 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
@@ -3702,8 +3710,23 @@ f_function(typval_T *argvars, typval_T *rettv)
}
pt->pt_refcount = 1;
- pt->pt_name = name;
- func_ref(pt->pt_name);
+ if (arg_pt != NULL && arg_pt->pt_func != NULL)
+ {
+ 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->vval.v_partial = pt;
@@ -3716,6 +3739,26 @@ f_function(typval_T *argvars, typval_T *rettv)
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)
{
char_u *what = get_tv_string(&argvars[1]);
+ char_u *n;
if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0)
{
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;
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)
{
@@ -10104,7 +10153,7 @@ item_compare2(const void *s1, const void *s2)
if (partial == NULL)
func_name = sortinfo->item_compare_func;
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
* 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)->pt_refcount;
- return (*pp)->pt_name;
+ return partial_name(*pp);
}
*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);
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)
return (char_u *)"";
EMSG(_("E921: Invalid callback argument"));
diff --git a/src/if_mzsch.c b/src/if_mzsch.c
index daec6b0a82..7a462ad54b 100644
--- a/src/if_mzsch.c
+++ b/src/if_mzsch.c
@@ -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. */
/* TODO: Support pt_dict and pt_argv. */
funcname = scheme_make_byte_string(
- (char *)vim_value->vval.v_partial->pt_name);
+ (char *)partial_name(vim_value->vval.v_partial));
MZ_GC_CHECK();
result = scheme_make_closed_prim_w_arity(vim_funcref, funcname,
(const char *)BYTE_STRING_VALUE(funcname), 0, -1);
diff --git a/src/if_py_both.h b/src/if_py_both.h
index 062f8226d7..4f916b7975 100644
--- a/src/if_py_both.h
+++ b/src/if_py_both.h
@@ -6310,7 +6310,7 @@ ConvertToPyObject(typval_T *tv)
if (tv->vval.v_partial->pt_dict != NULL)
tv->vval.v_partial->pt_dict->dv_refcount++;
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_dict,
tv->vval.v_partial->pt_auto);
diff --git a/src/misc2.c b/src/misc2.c
index 53469a261f..f44c33cea2 100644
--- a/src/misc2.c
+++ b/src/misc2.c
@@ -1217,16 +1217,20 @@ free_all_mem(void)
if (delete_first_msg() == FAIL)
break;
-# ifdef FEAT_EVAL
- eval_clear();
-# endif
# ifdef FEAT_JOB_CHANNEL
channel_free_all();
- job_free_all();
# endif
#ifdef FEAT_TIMERS
timer_free_all();
#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();
diff --git a/src/proto/eval.pro b/src/proto/eval.pro
index 56f0b49278..7a24683802 100644
--- a/src/proto/eval.pro
+++ b/src/proto/eval.pro
@@ -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 eval1(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);
int tv_equal(typval_T *tv1, typval_T *tv2, int ic, int recursive);
int get_copyID(void);
diff --git a/src/proto/userfunc.pro b/src/proto/userfunc.pro
index bd39604478..3988683cc5 100644
--- a/src/proto/userfunc.pro
+++ b/src/proto/userfunc.pro
@@ -3,9 +3,11 @@ void func_init(void);
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);
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);
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);
+char_u *trans_function_name(char_u **pp, int skip, int flags, funcdict_T *fdp, partial_T **partial);
void ex_function(exarg_T *eap);
int eval_fname_script(char_u *p);
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);
void ex_delfunction(exarg_T *eap);
void func_unref(char_u *name);
+void func_ptr_unref(ufunc_T *fp);
void func_ref(char_u *name);
+void func_ptr_ref(ufunc_T *fp);
void ex_return(exarg_T *eap);
void ex_call(exarg_T *eap);
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_call_stack(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 : */
diff --git a/src/regexp.c b/src/regexp.c
index 6b23cfbec9..6a685e30b3 100644
--- a/src/regexp.c
+++ b/src/regexp.c
@@ -7499,7 +7499,7 @@ vim_regsub_both(
{
partial_T *partial = expr->vval.v_partial;
- s = partial->pt_name;
+ s = partial_name(partial);
call_func(s, (int)STRLEN(s), &rettv,
1, argv, fill_submatch_list,
0L, 0L, &dummy, TRUE, partial, NULL);
diff --git a/src/structs.h b/src/structs.h
index 7375c7c2b8..11f182a77a 100644
--- a/src/structs.h
+++ b/src/structs.h
@@ -1295,10 +1295,100 @@ struct dictvar_S
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
{
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
dict.member in handle_subscript() */
int pt_argc; /* number of arguments */
diff --git a/src/testdir/test_expr.vim b/src/testdir/test_expr.vim
index d8abc27523..0800039aee 100644
--- a/src/testdir/test_expr.vim
+++ b/src/testdir/test_expr.vim
@@ -179,3 +179,18 @@ func Test_function_with_funcref()
call assert_equal(v:t_string, s:fref('x'))
call assert_fails("call function('s:f')", 'E700:')
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
diff --git a/src/testdir/test_lambda.vim b/src/testdir/test_lambda.vim
index 4d895460e5..721c47de11 100644
--- a/src/testdir/test_lambda.vim
+++ b/src/testdir/test_lambda.vim
@@ -152,7 +152,7 @@ function! Test_lambda_delfunc()
endfunction
let l:F = s:gen()
- call assert_fails(':call l:F()', 'E117:')
+ call assert_fails(':call l:F()', 'E933:')
endfunction
function! Test_lambda_scope()
diff --git a/src/userfunc.c b/src/userfunc.c
index d264e5bbbb..a9dc4e843d 100644
--- a/src/userfunc.c
+++ b/src/userfunc.c
@@ -14,52 +14,12 @@
#include "vim.h"
#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 */
#define FC_ABORT 1 /* abort function on error */
#define FC_RANGE 2 /* function accepts range */
#define FC_DICT 4 /* Dict function, uses "self" */
#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. */
#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 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.
*/
@@ -271,7 +185,7 @@ register_closure(ufunc_T *fp)
return FAIL;
((ufunc_T **)current_funccal->fc_funcs.ga_data)
[current_funccal->fc_funcs.ga_len++] = fp;
- func_ref(current_funccal->func->uf_name);
+ func_ptr_ref(current_funccal->func);
return OK;
}
@@ -288,7 +202,6 @@ get_lambda_tv(char_u **arg, typval_T *rettv, int evaluate)
ufunc_T *fp = NULL;
int varargs;
int ret;
- char_u name[20];
char_u *start = skipwhite(*arg + 1);
char_u *s, *e;
static int lambda_no = 0;
@@ -331,14 +244,22 @@ get_lambda_tv(char_u **arg, typval_T *rettv, int evaluate)
if (evaluate)
{
- int len, flags = 0;
- char_u *p;
+ int len, flags = 0;
+ char_u *p;
+ char_u name[20];
+ partial_T *pt;
sprintf((char*)name, "<lambda>%d", ++lambda_no);
fp = (ufunc_T *)alloc_clear((unsigned)(sizeof(ufunc_T) + STRLEN(name)));
if (fp == NULL)
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);
if (ga_grow(&newlines, 1) == FAIL)