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.
Files: src/vim.h, src/structs.h, src/userfunc.c, src/eval.c,
src/evalfunc.c, src/channel.c, src/proto/eval.pro,
src/proto/userfunc.pro, src/if_mzsch.c, src/regexp.c, src/misc2.c,
src/if_py_both.h, src/testdir/test_lambda.vim,
src/testdir/test_expr.vim, runtime/doc/eval.txt
*** ../vim-7.4.2136/src/vim.h 2016-07-31 14:11:55.178542370 +0200
--- src/vim.h 2016-07-31 20:50:02.276310616 +0200
***************
*** 2475,2480 ****
--- 2475,2481 ----
#define ERROR_DICT 4
#define ERROR_NONE 5
#define ERROR_OTHER 6
+ #define ERROR_DELETED 7
/* flags for find_name_end() */
#define FNE_INCL_BR 1 /* include [] in name */
*** ../vim-7.4.2136/src/structs.h 2016-07-22 21:49:36.666031534 +0200
--- src/structs.h 2016-07-31 21:51:09.928269249 +0200
***************
*** 1295,1304 ****
dict_T *dv_used_prev; /* previous dict in used dicts list */
};
struct partial_S
{
int pt_refcount; /* reference count */
! char_u *pt_name; /* function name */
int pt_auto; /* when TRUE the partial was created
for using
dict.member in handle_subscript() */
int pt_argc; /* number of arguments */
--- 1295,1394 ----
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; 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 */
*** ../vim-7.4.2136/src/userfunc.c 2016-07-31 18:30:19.037018267 +0200
--- src/userfunc.c 2016-08-01 13:06:05.408001028 +0200
***************
*** 14,65 ****
#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 */
/* From user function to hashitem and back. */
#define UF2HIKEY(fp) ((fp)->uf_name)
--- 14,25 ----
#include "vim.h"
#if defined(FEAT_EVAL) || defined(PROTO)
/* 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,120 ****
#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.
*/
--- 29,34 ----
***************
*** 271,277 ****
return FAIL;
((ufunc_T **)current_funccal->fc_funcs.ga_data)
[current_funccal->fc_funcs.ga_len++] = fp;
! func_ref(current_funccal->func->uf_name);
return OK;
}
--- 185,191 ----
return FAIL;
((ufunc_T **)current_funccal->fc_funcs.ga_data)
[current_funccal->fc_funcs.ga_len++] = fp;
! func_ptr_ref(current_funccal->func);
return OK;
}
***************
*** 288,294 ****
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;
--- 202,207 ----
***************
*** 331,344 ****
if (evaluate)
{
! int len, flags = 0;
! char_u *p;
sprintf((char*)name, "<lambda>%d", ++lambda_no);
fp = (ufunc_T *)alloc_clear((unsigned)(sizeof(ufunc_T) + STRLEN(name)));
if (fp == NULL)
goto errret;
ga_init2(&newlines, (int)sizeof(char_u *), 1);
if (ga_grow(&newlines, 1) == FAIL)
--- 244,265 ----
if (evaluate)
{
! 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)
***************
*** 380,387 ****
fp->uf_calls = 0;
fp->uf_script_ID = current_SID;
! rettv->vval.v_string = vim_strsave(name);
! rettv->v_type = VAR_FUNC;
}
eval_lavars_used = old_eval_lavars;
--- 301,310 ----
fp->uf_calls = 0;
fp->uf_script_ID = current_SID;
! pt->pt_func = fp;
! pt->pt_refcount = 1;
! rettv->vval.v_partial = pt;
! rettv->v_type = VAR_PARTIAL;
}
eval_lavars_used = old_eval_lavars;
***************
*** 406,411 ****
--- 329,335 ----
{
dictitem_T *v;
int cc;
+ char_u *s;
if (partialp != NULL)
*partialp = NULL;
***************
*** 421,428 ****
*lenp = 0;
return (char_u *)""; /* just in case */
}
! *lenp = (int)STRLEN(v->di_tv.vval.v_string);
! return v->di_tv.vval.v_string;
}
if (v != NULL && v->di_tv.v_type == VAR_PARTIAL)
--- 345,353 ----
*lenp = 0;
return (char_u *)""; /* just in case */
}
! s = v->di_tv.vval.v_string;
! *lenp = (int)STRLEN(s);
! return s;
}
if (v != NULL && v->di_tv.v_type == VAR_PARTIAL)
***************
*** 436,443 ****
}
if (partialp != NULL)
*partialp = pt;
! *lenp = (int)STRLEN(pt->pt_name);
! return pt->pt_name;
}
return name;
--- 361,369 ----
}
if (partialp != NULL)
*partialp = pt;
! s = partial_name(pt);
! *lenp = (int)STRLEN(s);
! return s;
}
return name;
***************
*** 611,617 ****
* Find a function by name, return pointer to it in ufuncs.
* Return NULL for unknown function.
*/
! static ufunc_T *
find_func(char_u *name)
{
hashitem_T *hi;
--- 537,543 ----
* Find a function by name, return pointer to it in ufuncs.
* Return NULL for unknown function.
*/
! ufunc_T *
find_func(char_u *name)
{
hashitem_T *hi;
***************
*** 678,684 ****
* funccall_T, don't clear it then. */
if (fp->uf_scoped == fc)
fp->uf_scoped = NULL;
! func_unref(fc->func->uf_name);
}
}
ga_clear(&fc->fc_funcs);
--- 604,610 ----
* funccall_T, don't clear it then. */
if (fp->uf_scoped == fc)
fp->uf_scoped = NULL;
! func_ptr_unref(fc->func);
}
}
ga_clear(&fc->fc_funcs);
***************
*** 695,701 ****
for (li = fc->l_varlist.lv_first; li != NULL; li = li->li_next)
clear_tv(&li->li_tv);
! func_unref(fc->func->uf_name);
vim_free(fc);
}
--- 621,627 ----
for (li = fc->l_varlist.lv_first; li != NULL; li = li->li_next)
clear_tv(&li->li_tv);
! func_ptr_unref(fc->func);
vim_free(fc);
}
***************
*** 759,765 ****
fc->fc_refcount = 0;
fc->fc_copyID = 0;
ga_init2(&fc->fc_funcs, sizeof(ufunc_T *), 1);
! func_ref(fp->uf_name);
if (STRNCMP(fp->uf_name, "<lambda>", 8) == 0)
islambda = TRUE;
--- 685,691 ----
fc->fc_refcount = 0;
fc->fc_copyID = 0;
ga_init2(&fc->fc_funcs, sizeof(ufunc_T *), 1);
! func_ptr_ref(fp);
if (STRNCMP(fp->uf_name, "<lambda>", 8) == 0)
islambda = TRUE;
***************
*** 1112,1135 ****
if (--fc->fc_refcount <= 0)
{
! for (pfc = &previous_funccal; *pfc != NULL; )
{
! if (fc == *pfc
! && fc->l_varlist.lv_refcount == DO_NOT_FREE_CNT
&& fc->l_vars.dv_refcount == DO_NOT_FREE_CNT
&& fc->l_avars.dv_refcount == DO_NOT_FREE_CNT)
! {
! *pfc = fc->caller;
! free_funccal(fc, TRUE);
! freed = TRUE;
}
- else
- pfc = &(*pfc)->caller;
}
}
if (!freed)
{
! func_unref(fc->func->uf_name);
if (fp != NULL)
for (i = 0; i < fc->fc_funcs.ga_len; ++i)
--- 1038,1062 ----
if (--fc->fc_refcount <= 0)
{
! for (pfc = &previous_funccal; *pfc != NULL; pfc = &(*pfc)->caller)
{
! if (fc == *pfc)
! {
! if (fc->l_varlist.lv_refcount == DO_NOT_FREE_CNT
&& fc->l_vars.dv_refcount == DO_NOT_FREE_CNT
&& fc->l_avars.dv_refcount == DO_NOT_FREE_CNT)
! {
! *pfc = fc->caller;
! free_funccal(fc, TRUE);
! freed = TRUE;
! }
! break;
}
}
}
if (!freed)
{
! func_ptr_unref(fc->func);
if (fp != NULL)
for (i = 0; i < fc->fc_funcs.ga_len; ++i)
***************
*** 1141,1153 ****
}
/*
* Free a function and remove it from the list of functions.
*/
static void
func_free(ufunc_T *fp)
{
- hashitem_T *hi;
-
/* clear this function */
ga_clear_strings(&(fp->uf_args));
ga_clear_strings(&(fp->uf_lines));
--- 1068,1091 ----
}
/*
+ * 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.
*/
static void
func_free(ufunc_T *fp)
{
/* clear this function */
ga_clear_strings(&(fp->uf_args));
ga_clear_strings(&(fp->uf_lines));
***************
*** 1156,1168 ****
vim_free(fp->uf_tml_total);
vim_free(fp->uf_tml_self);
#endif
!
! /* 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);
--- 1094,1100 ----
vim_free(fp->uf_tml_total);
vim_free(fp->uf_tml_self);
#endif
! func_remove(fp);
funccal_unref(fp->uf_scoped, fp);
***************
*** 1333,1339 ****
/*
* User defined function.
*/
! fp = find_func(rfname);
#ifdef FEAT_AUTOCMD
/* Trigger FuncUndefined event, may load the function. */
--- 1265,1274 ----
/*
* User defined function.
*/
! if (partial != NULL && partial->pt_func != NULL)
! fp = partial->pt_func;
! else
! fp = find_func(rfname);
#ifdef FEAT_AUTOCMD
/* Trigger FuncUndefined event, may load the function. */
***************
*** 1353,1359 ****
fp = find_func(rfname);
}
! if (fp != NULL)
{
if (argv_func != NULL)
argcount = argv_func(argcount, argvars, fp->uf_args.ga_len);
--- 1288,1296 ----
fp = find_func(rfname);
}
! if (fp != NULL && (fp->uf_flags & FC_DELETED))
! error = ERROR_DELETED;
! else if (fp != NULL)
{
if (argv_func != NULL)
argcount = argv_func(argcount, argvars, fp->uf_args.ga_len);
***************
*** 1387,1395 ****
call_user_func(fp, argcount, argvars, rettv,
firstline, lastline,
(fp->uf_flags & FC_DICT) ? selfdict : NULL);
! if (--fp->uf_calls <= 0 && (isdigit(*fp->uf_name)
! || STRNCMP(fp->uf_name, "<lambda>", 8) == 0)
! && fp->uf_refcount <= 0)
/* Function was unreferenced while being used, free it
* now. */
func_free(fp);
--- 1324,1330 ----
call_user_func(fp, argcount, argvars, rettv,
firstline, lastline,
(fp->uf_flags & FC_DICT) ? selfdict : NULL);
! if (--fp->uf_calls <= 0 && fp->uf_refcount <= 0)
/* Function was unreferenced while being used, free it
* now. */
func_free(fp);
***************
*** 1433,1438 ****
--- 1368,1376 ----
case ERROR_UNKNOWN:
emsg_funcname(N_("E117: Unknown function: %s"), name);
break;
+ case ERROR_DELETED:
+ emsg_funcname(N_("E933: Function was deleted: %s"), name);
+ break;
case ERROR_TOOMANY:
emsg_funcname((char *)e_toomanyarg, name);
break;
***************
*** 1516,1522 ****
* TFN_NO_DEREF: do not dereference a Funcref
* Advances "pp" to just after the function name (if no error).
*/
! static char_u *
trans_function_name(
char_u **pp,
int skip, /* only find the end, don't evaluate */
--- 1454,1460 ----
* TFN_NO_DEREF: do not dereference a Funcref
* Advances "pp" to just after the function name (if no error).
*/
! char_u *
trans_function_name(
char_u **pp,
int skip, /* only find the end, don't evaluate */
***************
*** 1595,1601 ****
else if (lv.ll_tv->v_type == VAR_PARTIAL
&& lv.ll_tv->vval.v_partial != NULL)
{
! name = vim_strsave(lv.ll_tv->vval.v_partial->pt_name);
*pp = end;
if (partial != NULL)
*partial = lv.ll_tv->vval.v_partial;
--- 1533,1539 ----
else if (lv.ll_tv->v_type == VAR_PARTIAL
&& lv.ll_tv->vval.v_partial != NULL)
{
! name = vim_strsave(partial_name(lv.ll_tv->vval.v_partial));
*pp = end;
if (partial != NULL)
*partial = lv.ll_tv->vval.v_partial;
***************
*** 1752,1757 ****
--- 1690,1696 ----
int varargs = FALSE;
int flags = 0;
ufunc_T *fp;
+ int overwrite = FALSE;
int indent;
int nesting;
char_u *skip_until = NULL;
***************
*** 2214,2224 ****
name);
goto erret;
}
! /* redefine existing function */
! ga_clear_strings(&(fp->uf_args));
! ga_clear_strings(&(fp->uf_lines));
! vim_free(name);
! name = NULL;
}
}
else
--- 2153,2174 ----
name);
goto erret;
}
! if (fp->uf_refcount > 1)
! {
! /* This function is referenced somewhere, don't redefine it but
! * create a new one. */
! --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
***************
*** 2308,2314 ****
fudi.fd_di->di_tv.v_type = VAR_FUNC;
fudi.fd_di->di_tv.v_lock = 0;
fudi.fd_di->di_tv.vval.v_string = vim_strsave(name);
- fp->uf_refcount = 1;
/* behave like "dict" was used */
flags |= FC_DICT;
--- 2258,2263 ----
***************
*** 2316,2332 ****
/* insert the new function in the function list */
STRCPY(fp->uf_name, name);
! if (hash_add(&func_hashtab, UF2HIKEY(fp)) == FAIL)
{
vim_free(fp);
goto erret;
}
}
fp->uf_args = newargs;
fp->uf_lines = newlines;
if ((flags & FC_CLOSURE) != 0)
{
- ++fp->uf_refcount;
if (register_closure(fp) == FAIL)
goto erret;
}
--- 2265,2286 ----
/* insert the new function in the function list */
STRCPY(fp->uf_name, name);
! 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);
goto erret;
}
+ fp->uf_refcount = 1;
}
fp->uf_args = newargs;
fp->uf_lines = newlines;
if ((flags & FC_CLOSURE) != 0)
{
if (register_closure(fp) == FAIL)
goto erret;
}
***************
*** 2750,2762 ****
dictitem_remove(fudi.fd_dict, fudi.fd_di);
}
else
! func_free(fp);
}
}
/*
* Unreference a Function: decrement the reference count and free it when it
! * becomes zero. Only for numbered functions.
*/
void
func_unref(char_u *name)
--- 2704,2733 ----
dictitem_remove(fudi.fd_dict, fudi.fd_di);
}
else
! {
! /* 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
! * becomes zero.
*/
void
func_unref(char_u *name)
***************
*** 2765,2786 ****
if (name == NULL)
return;
! if (isdigit(*name))
{
- fp = find_func(name);
- if (fp == NULL)
- {
#ifdef EXITFREE
! if (!entered_free_all_mem)
#endif
! EMSG2(_(e_intern2), "func_unref()");
! }
}
! else if (STRNCMP(name, "<lambda>", 8) == 0)
{
! /* fail silently, when lambda function isn't found. */
! fp = find_func(name);
}
if (fp != NULL && --fp->uf_refcount <= 0)
{
/* Only delete it when it's not being used. Otherwise it's done
--- 2736,2765 ----
if (name == NULL)
return;
! fp = find_func(name);
! if (fp == NULL && isdigit(*name))
{
#ifdef EXITFREE
! if (!entered_free_all_mem)
#endif
! EMSG2(_(e_intern2), "func_unref()");
}
! if (fp != NULL && --fp->uf_refcount <= 0)
{
! /* Only delete it when it's not being used. Otherwise it's done
! * 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)
{
/* Only delete it when it's not being used. Otherwise it's done
***************
*** 2800,2820 ****
if (name == NULL)
return;
else if (isdigit(*name))
! {
! fp = find_func(name);
! if (fp == NULL)
! EMSG2(_(e_intern2), "func_ref()");
! else
! ++fp->uf_refcount;
! }
! else if (STRNCMP(name, "<lambda>", 8) == 0)
! {
! /* fail silently, when lambda function isn't found. */
! fp = find_func(name);
! if (fp != NULL)
! ++fp->uf_refcount;
! }
}
/*
--- 2779,2801 ----
if (name == NULL)
return;
+ fp = find_func(name);
+ if (fp != NULL)
+ ++fp->uf_refcount;
else if (isdigit(*name))
! /* Only give an error for a numbered function.
! * Fail silently, when named or lambda function isn't found. */
! EMSG2(_(e_intern2), "func_ref()");
! }
!
! /*
! * Count a reference to a Function.
! */
! void
! func_ptr_ref(ufunc_T *fp)
! {
! if (fp != NULL)
! ++fp->uf_refcount;
}
/*
***************
*** 3298,3315 ****
dict_T *
make_partial(dict_T *selfdict_in, typval_T *rettv)
{
! char_u *fname = rettv->v_type == VAR_FUNC ? rettv->vval.v_string
! : rettv->vval.v_partial->pt_name;
char_u *tofree = NULL;
ufunc_T *fp;
char_u fname_buf[FLEN_FIXED + 1];
int error;
dict_T *selfdict = selfdict_in;
! /* 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))
{
--- 3279,3302 ----
dict_T *
make_partial(dict_T *selfdict_in, typval_T *rettv)
{
! char_u *fname;
char_u *tofree = NULL;
ufunc_T *fp;
char_u fname_buf[FLEN_FIXED + 1];
int error;
dict_T *selfdict = selfdict_in;
! if (rettv->v_type == VAR_PARTIAL && rettv->vval.v_partial->pt_func !=
NULL)
! fp = rettv->vval.v_partial->pt_func;
! else
! {
! 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))
{
***************
*** 3335,3342 ****
/* Partial: copy the function name, use selfdict and copy
* args. Can't take over name or args, the partial might
* be referenced elsewhere. */
! pt->pt_name = vim_strsave(ret_pt->pt_name);
! func_ref(pt->pt_name);
if (ret_pt->pt_argc > 0)
{
pt->pt_argv = (typval_T *)alloc(
--- 3322,3337 ----
/* Partial: copy the function name, use selfdict and copy
* args. Can't take over name or args, the partial might
* be referenced elsewhere. */
! if (ret_pt->pt_name != NULL)
! {
! 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)
{
pt->pt_argv = (typval_T *)alloc(
***************
*** 3703,3722 ****
* Returns TRUE if setting references failed somehow.
*/
int
! set_ref_in_func(char_u *name, int copyID)
{
! ufunc_T *fp;
funccall_T *fc;
int error = ERROR_NONE;
char_u fname_buf[FLEN_FIXED + 1];
char_u *tofree = NULL;
char_u *fname;
! if (name == NULL)
return FALSE;
! fname = fname_trans_sid(name, fname_buf, &tofree, &error);
! fp = find_func(fname);
if (fp != NULL)
{
for (fc = fp->uf_scoped; fc != NULL; fc = fc->func->uf_scoped)
--- 3698,3720 ----
* Returns TRUE if setting references failed somehow.
*/
int
! set_ref_in_func(char_u *name, ufunc_T *fp_in, int copyID)
{
! ufunc_T *fp = fp_in;
funccall_T *fc;
int error = ERROR_NONE;
char_u fname_buf[FLEN_FIXED + 1];
char_u *tofree = NULL;
char_u *fname;
! if (name == NULL && fp_in == NULL)
return FALSE;
! if (fp_in == NULL)
! {
! fname = fname_trans_sid(name, fname_buf, &tofree, &error);
! fp = find_func(fname);
! }
if (fp != NULL)
{
for (fc = fp->uf_scoped; fc != NULL; fc = fc->func->uf_scoped)
*** ../vim-7.4.2136/src/eval.c 2016-07-31 14:11:55.174542407 +0200
--- src/eval.c 2016-07-31 19:48:04.116443706 +0200
***************
*** 5011,5016 ****
--- 5011,5027 ----
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,5027 ****
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);
vim_free(pt);
}
--- 5031,5043 ----
clear_tv(&pt->pt_argv[i]);
vim_free(pt->pt_argv);
dict_unref(pt->pt_dict);
! 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,5061 ****
/* empty and NULL function name considered the same */
s1 = tv1->v_type == VAR_FUNC ? tv1->vval.v_string
! : tv1->vval.v_partial->pt_name;
if (s1 != NULL && *s1 == NUL)
s1 = NULL;
s2 = tv2->v_type == VAR_FUNC ? tv2->vval.v_string
! : tv2->vval.v_partial->pt_name;
if (s2 != NULL && *s2 == NUL)
s2 = NULL;
if (s1 == NULL || s2 == NULL)
--- 5067,5077 ----
/* empty and NULL function name considered the same */
s1 = tv1->v_type == VAR_FUNC ? tv1->vval.v_string
! : partial_name(tv1->vval.v_partial);
if (s1 != NULL && *s1 == NUL)
s1 = NULL;
s2 = tv2->v_type == VAR_FUNC ? tv2->vval.v_string
! : partial_name(tv2->vval.v_partial);
if (s2 != NULL && *s2 == NUL)
s2 = NULL;
if (s1 == NULL || s2 == NULL)
***************
*** 5550,5556 ****
}
else if (tv->v_type == VAR_FUNC)
{
! abort = set_ref_in_func(tv->vval.v_string, copyID);
}
else if (tv->v_type == VAR_PARTIAL)
{
--- 5566,5572 ----
}
else if (tv->v_type == VAR_FUNC)
{
! abort = set_ref_in_func(tv->vval.v_string, NULL, copyID);
}
else if (tv->v_type == VAR_PARTIAL)
{
***************
*** 5561,5567 ****
*/
if (pt != NULL)
{
! abort = set_ref_in_func(pt->pt_name, copyID);
if (pt->pt_dict != NULL)
{
--- 5577,5583 ----
*/
if (pt != NULL)
{
! abort = set_ref_in_func(pt->pt_name, pt->pt_func, copyID);
if (pt->pt_dict != NULL)
{
***************
*** 5735,5741 ****
{
partial_T *pt = tv->vval.v_partial;
char_u *fname = string_quote(pt == NULL ? NULL
! : pt->pt_name, FALSE);
garray_T ga;
int i;
char_u *tf;
--- 5751,5757 ----
{
partial_T *pt = tv->vval.v_partial;
char_u *fname = string_quote(pt == NULL ? NULL
! : partial_name(pt), FALSE);
garray_T ga;
int i;
char_u *tf;
***************
*** 6871,6877 ****
if (functv.v_type == VAR_PARTIAL)
{
pt = functv.vval.v_partial;
! s = pt->pt_name;
}
else
s = functv.vval.v_string;
--- 6887,6893 ----
if (functv.v_type == VAR_PARTIAL)
{
pt = functv.vval.v_partial;
! s = partial_name(pt);
}
else
s = functv.vval.v_string;
***************
*** 10025,10031 ****
{
partial_T *partial = expr->vval.v_partial;
! s = partial->pt_name;
if (call_func(s, (int)STRLEN(s), &rettv, 2, argv, NULL,
0L, 0L, &dummy, TRUE, partial, NULL) == FAIL)
goto theend;
--- 10041,10047 ----
{
partial_T *partial = expr->vval.v_partial;
! s = partial_name(partial);
if (call_func(s, (int)STRLEN(s), &rettv, 2, argv, NULL,
0L, 0L, &dummy, TRUE, partial, NULL) == FAIL)
goto theend;
*** ../vim-7.4.2136/src/evalfunc.c 2016-07-31 14:11:55.178542370 +0200
--- src/evalfunc.c 2016-08-01 15:27:58.610785732 +0200
***************
*** 148,153 ****
--- 148,154 ----
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,568 ****
--- 564,570 ----
{"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,1729 ****
else if (argvars[0].v_type == VAR_PARTIAL)
{
partial = argvars[0].vval.v_partial;
! func = partial->pt_name;
}
else
func = get_tv_string(&argvars[0]);
--- 1725,1731 ----
else if (argvars[0].v_type == VAR_PARTIAL)
{
partial = argvars[0].vval.v_partial;
! func = partial_name(partial);
}
else
func = get_tv_string(&argvars[0]);
***************
*** 3543,3558 ****
#endif
}
- /*
- * "function()" function
- */
static void
! f_function(typval_T *argvars, typval_T *rettv)
{
char_u *s;
char_u *name;
int use_string = FALSE;
partial_T *arg_pt = NULL;
if (argvars[0].v_type == VAR_FUNC)
{
--- 3545,3558 ----
#endif
}
static void
! 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,3570 ****
{
/* function(dict.MyFunc, [arg]) */
arg_pt = argvars[0].vval.v_partial;
! s = arg_pt->pt_name;
}
else
{
--- 3564,3570 ----
{
/* function(dict.MyFunc, [arg]) */
arg_pt = argvars[0].vval.v_partial;
! s = partial_name(arg_pt);
}
else
{
***************
*** 3573,3583 ****
use_string = TRUE;
}
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))
EMSG2(_("E700: Unknown function: %s"), s);
else
{
--- 3573,3594 ----
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 (trans_name != NULL && (is_funcref
! ? find_func(trans_name) == NULL
! : !translated_function_exists(trans_name)))
EMSG2(_("E700: Unknown function: %s"), s);
else
{
***************
*** 3625,3631 ****
{
EMSG(_("E922: expected a dict"));
vim_free(name);
! return;
}
if (argvars[dict_idx].vval.v_dict == NULL)
dict_idx = 0;
--- 3636,3642 ----
{
EMSG(_("E922: expected a dict"));
vim_free(name);
! goto theend;
}
if (argvars[dict_idx].vval.v_dict == NULL)
dict_idx = 0;
***************
*** 3636,3649 ****
{
EMSG(_("E923: Second argument of function() must be a list
or a dict"));
vim_free(name);
! return;
}
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)
{
partial_T *pt = (partial_T *)alloc_clear(sizeof(partial_T));
--- 3647,3660 ----
{
EMSG(_("E923: Second argument of function() must be a list
or a dict"));
vim_free(name);
! 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 || is_funcref)
{
partial_T *pt = (partial_T *)alloc_clear(sizeof(partial_T));
***************
*** 3670,3686 ****
{
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++]);
}
}
/* For "function(dict.func, [], dict)" and "func" is a partial
--- 3681,3694 ----
{
vim_free(pt);
vim_free(name);
! 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,3709 ****
}
pt->pt_refcount = 1;
! pt->pt_name = name;
! func_ref(pt->pt_name);
}
rettv->v_type = VAR_PARTIAL;
rettv->vval.v_partial = pt;
--- 3710,3732 ----
}
pt->pt_refcount = 1;
! 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,3721 ****
--- 3739,3764 ----
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,3794 ****
if (pt != NULL)
{
char_u *what = get_tv_string(&argvars[1]);
if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0)
{
rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING);
! if (pt->pt_name == NULL)
rettv->vval.v_string = NULL;
else
! rettv->vval.v_string = vim_strsave(pt->pt_name);
}
else if (STRCMP(what, "dict") == 0)
{
--- 3824,3843 ----
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);
! n = partial_name(pt);
! if (n == NULL)
rettv->vval.v_string = NULL;
else
! {
! 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,10110 ****
if (partial == NULL)
func_name = sortinfo->item_compare_func;
else
! func_name = partial->pt_name;
/* 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. */
--- 10153,10159 ----
if (partial == NULL)
func_name = sortinfo->item_compare_func;
else
! 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,11878 ****
{
*pp = arg->vval.v_partial;
++(*pp)->pt_refcount;
! return (*pp)->pt_name;
}
*pp = NULL;
! if (arg->v_type == VAR_FUNC)
{
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"));
--- 11912,11925 ----
{
*pp = arg->vval.v_partial;
++(*pp)->pt_refcount;
! return partial_name(*pp);
}
*pp = NULL;
! 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_NUMBER && arg->vval.v_number == 0)
return (char_u *)"";
EMSG(_("E921: Invalid callback argument"));
*** ../vim-7.4.2136/src/channel.c 2016-07-30 23:05:04.720679001 +0200
--- src/channel.c 2016-08-01 13:52:46.034799279 +0200
***************
*** 1124,1138 ****
if (callback != NULL && *callback != NUL)
{
if (partial != NULL)
! *cbp = partial->pt_name;
else
*cbp = vim_strsave(callback);
}
else
*cbp = NULL;
*pp = partial;
! if (*pp != NULL)
! ++(*pp)->pt_refcount;
}
/*
--- 1124,1141 ----
if (callback != NULL && *callback != NUL)
{
if (partial != NULL)
! *cbp = partial_name(partial);
else
+ {
*cbp = vim_strsave(callback);
+ func_ref(*cbp);
+ }
}
else
*cbp = NULL;
*pp = partial;
! if (partial != NULL)
! ++partial->pt_refcount;
}
/*
***************
*** 1279,1285 ****
--- 1282,1291 ----
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,3936 ****
--- 3929,3952 ----
{
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,4482 ****
--- 4492,4501 ----
++job->jv_exit_partial->pt_refcount;
}
else
+ {
job->jv_exit_cb = vim_strsave(opt->jo_exit_cb);
+ func_ref(job->jv_exit_cb);
+ }
}
}
}
*** ../vim-7.4.2136/src/proto/eval.pro 2016-07-29 22:14:39.035998293 +0200
--- src/proto/eval.pro 2016-07-31 19:47:47.492588175 +0200
***************
*** 40,45 ****
--- 40,46 ----
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);
*** ../vim-7.4.2136/src/proto/userfunc.pro 2016-07-31 14:11:55.178542370
+0200
--- src/proto/userfunc.pro 2016-07-31 21:51:37.416028064 +0200
***************
*** 3,11 ****
--- 3,13 ----
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,23 ****
--- 19,27 ----
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,55 ****
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);
/* vim: set ft=c : */
--- 55,59 ----
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, ufunc_T *fp_in, int copyID);
/* vim: set ft=c : */
*** ../vim-7.4.2136/src/if_mzsch.c 2016-07-24 21:58:39.704057634 +0200
--- src/if_mzsch.c 2016-07-31 19:39:28.032924413 +0200
***************
*** 3134,3140 ****
/* 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);
MZ_GC_CHECK();
result = scheme_make_closed_prim_w_arity(vim_funcref, funcname,
(const char *)BYTE_STRING_VALUE(funcname), 0, -1);
--- 3134,3140 ----
/* FIXME: func_ref() and func_unref() are needed. */
/* TODO: Support pt_dict and pt_argv. */
funcname = scheme_make_byte_string(
! (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);
*** ../vim-7.4.2136/src/regexp.c 2016-07-22 21:49:36.678031435 +0200
--- src/regexp.c 2016-07-31 19:39:49.816735470 +0200
***************
*** 7499,7505 ****
{
partial_T *partial = expr->vval.v_partial;
! s = partial->pt_name;
call_func(s, (int)STRLEN(s), &rettv,
1, argv, fill_submatch_list,
0L, 0L, &dummy, TRUE, partial, NULL);
--- 7499,7505 ----
{
partial_T *partial = expr->vval.v_partial;
! s = partial_name(partial);
call_func(s, (int)STRLEN(s), &rettv,
1, argv, fill_submatch_list,
0L, 0L, &dummy, TRUE, partial, NULL);
*** ../vim-7.4.2136/src/misc2.c 2016-07-30 22:47:44.322520729 +0200
--- src/misc2.c 2016-07-31 20:10:26.272891113 +0200
***************
*** 1217,1232 ****
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
free_termoptions();
--- 1217,1236 ----
if (delete_first_msg() == FAIL)
break;
# ifdef FEAT_JOB_CHANNEL
channel_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();
*** ../vim-7.4.2136/src/if_py_both.h 2016-07-10 22:11:11.878751222 +0200
--- src/if_py_both.h 2016-07-31 19:42:27.039371291 +0200
***************
*** 6310,6316 ****
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,
tv->vval.v_partial->pt_argc, argv,
tv->vval.v_partial->pt_dict,
tv->vval.v_partial->pt_auto);
--- 6310,6316 ----
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 *)"" : 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);
*** ../vim-7.4.2136/src/testdir/test_lambda.vim 2016-07-31 18:30:19.041018233
+0200
--- src/testdir/test_lambda.vim 2016-08-01 14:37:05.886717455 +0200
***************
*** 152,158 ****
endfunction
let l:F = s:gen()
! call assert_fails(':call l:F()', 'E117:')
endfunction
function! Test_lambda_scope()
--- 152,158 ----
endfunction
let l:F = s:gen()
! call assert_fails(':call l:F()', 'E933:')
endfunction
function! Test_lambda_scope()
*** ../vim-7.4.2136/src/testdir/test_expr.vim 2016-07-31 14:11:55.178542370
+0200
--- src/testdir/test_expr.vim 2016-08-01 15:22:51.561635890 +0200
***************
*** 179,181 ****
--- 179,196 ----
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
*** ../vim-7.4.2136/runtime/doc/eval.txt 2016-07-29 22:36:40.207701429
+0200
--- runtime/doc/eval.txt 2016-07-31 21:23:15.218976743 +0200
***************
*** 2052,2059 ****
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 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}
--- 2073,2082 ----
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
+ 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}
***************
*** 3829,3842 ****
{only in the Win32, Athena, Motif and GTK GUI versions and the
Win32 console version}
*function()* *E700* *E922* *E923*
function({name} [, {arglist}] [, {dict}])
Return a |Funcref| variable that refers to function {name}.
! {name} can be a user defined function or an internal function.
When {arglist} or {dict} is present this creates a partial.
! That mans the argument list and/or the dictionary is stored in
the Funcref and will be used when the Funcref is called.
The arguments are passed to the function in front of other
--- 3854,3887 ----
{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}])
Return a |Funcref| variable that refers to function {name}.
! {name} can be the name of a user defined function or an
! internal function.
!
! {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.
The arguments are passed to the function in front of other
***************
*** 3849,3854 ****
--- 3894,3911 ----
< Invokes the function as with: >
call Callback('one', 'two', 'name')
+ < The function() call can be nested to add more arguments to the
+ Funcref. The extra arguments are appended to the list of
+ arguments. Example: >
+ func Callback(arg1, arg2, name)
+ ...
+ let Func = function('Callback', ['one'])
+ let Func2 = function(Func, ['two'])
+ ...
+ call Func2('name')
+ < Invokes the function as with: >
+ call Callback('one', 'two', 'name')
+
< The Dictionary is only useful when calling a "dict" function.
In that case the {dict} is passed in as "self". Example: >
function Callback() dict
***************
*** 3859,3864 ****
--- 3916,3925 ----
let Func = function('Callback', context)
...
call Func() " will echo: called for example
+ < The use of function() is not needed when there are no extra
+ arguments, these two are equivalent: >
+ let Func = function('Callback', context)
+ let Func = context.Callback
< The argument list and the Dictionary can be combined: >
function Callback(arg1, count) dict
*** ../vim-7.4.2136/src/version.c 2016-07-31 18:30:19.041018233 +0200
--- src/version.c 2016-08-01 15:24:17.452838262 +0200
***************
*** 765,766 ****
--- 765,768 ----
{ /* Add new patch number below this line */
+ /**/
+ 2137,
/**/
--
MICHAEL PALIN PLAYED: 1ST SOLDIER WITH A KEEN INTEREST IN BIRDS, DENNIS, MR
DUCK (A VILLAGE CARPENTER WHO IS ALMOST KEENER THAN
ANYONE ELSE TO BURN WITCHES), THREE-HEADED KNIGHT, SIR
GALAHAD, KING OF SWAMP CASTLE, BROTHER MAYNARD'S ROOMATE
"Monty Python and the Holy Grail" PYTHON (MONTY) PICTURES LTD
/// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net \\\
/// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
\\\ an exciting new programming language -- http://www.Zimbu.org ///
\\\ help me help AIDS victims -- http://ICCF-Holland.org ///
--
--
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php
---
You received this message because you are subscribed to the Google Groups
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.