To: vim_dev@googlegroups.com Subject: Patch 7.4.2137 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ 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 123_ ( 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 123_ ( 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, "%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, "%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, "", 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, "", 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, "", 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, "", 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, "", 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 -- Bram@Moolenaar.net -- 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 ///