Last active
January 17, 2022 08:46
-
-
Save mattn/50fa1dc854911d5cb797 to your computer and use it in GitHub Desktop.
Vim script に lambda 関数を追加するパッチ
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff -r 1b74025a66e7 runtime/doc/eval.txt | |
--- a/runtime/doc/eval.txt Sat Sep 27 11:18:20 2014 +0200 | |
+++ b/runtime/doc/eval.txt Sun Sep 28 23:39:50 2014 +0900 | |
@@ -1869,6 +1869,7 @@ | |
join( {list} [, {sep}]) String join {list} items into one String | |
keys( {dict}) List keys in {dict} | |
len( {expr}) Number the length of {expr} | |
+lambda( {expr}) Create lambda function constructed with {expr} | |
libcall( {lib}, {func}, {arg}) String call {func} in library {lib} with {arg} | |
libcallnr( {lib}, {func}, {arg}) Number idem, but return a Number | |
line( {expr}) Number line nr of cursor, last line or mark | |
@@ -2996,11 +2997,12 @@ | |
directory, and we can write to it, the result is 2. | |
-filter({expr}, {string}) *filter()* | |
- {expr} must be a |List| or a |Dictionary|. | |
- For each item in {expr} evaluate {string} and when the result | |
+filter({expr1}, {expr2}) *filter()* | |
+ {expr1} must be a |List| or a |Dictionary|. | |
+ For each item in {expr1} evaluate {string} and when the result | |
is zero remove the item from the |List| or |Dictionary|. | |
- Inside {string} |v:val| has the value of the current item. | |
+ {expr2} must be a |string| or |Funcref|. If it's |string|, | |
+ inside {expr2} |v:val| has the value of the current item. | |
For a |Dictionary| |v:key| has the key of the current item. | |
Examples: > | |
:call filter(mylist, 'v:val !~ "OLD"') | |
@@ -3010,7 +3012,7 @@ | |
:call filter(var, 0) | |
< Removes all the items, thus clears the |List| or |Dictionary|. | |
- Note that {string} is the result of expression and is then | |
+ Note that {expr2} is the result of expression and is then | |
used as an expression again. Often it is good to use a | |
|literal-string| to avoid having to double backslashes. | |
@@ -3018,9 +3020,13 @@ | |
|Dictionary| to remain unmodified make a copy first: > | |
:let l = filter(copy(mylist), 'v:val =~ "KEEP"') | |
-< Returns {expr}, the |List| or |Dictionary| that was filtered. | |
- When an error is encountered while evaluating {string} no | |
- further items in {expr} are processed. | |
+< Returns {expr1}, the |List| or |Dictionary| that was filtered. | |
+ When an error is encountered while evaluating {expr2} no | |
+ further items in {expr1} are processed. | |
+ | |
+ {expr2} is possible to be given as |Funcref|. The function | |
+ should return TRUE if the item should be kept. The value is | |
+ given as "a:1". | |
finddir({name}[, {path}[, {count}]]) *finddir()* | |
@@ -4038,6 +4044,60 @@ | |
|Dictionary| is returned. | |
Otherwise an error is given. | |
+ *lambda()* | |
+lambda({expr}) | |
+ Create new lambda function with constructed with {expr}. | |
+ The result is function reference. So you can call it like. | |
+ Example: | |
+ :let F = lambda("return 1+2") | |
+ :echo F() | |
+ | |
+ Lambda function allow to be given variadic arguments. | |
+ Example: | |
+ :let F = lambda("return a:1+2") | |
+ :echo F(2) | |
+ | |
+ |sort()|, |map()|, |filter()| can be used with |lambda()| | |
+ Example: | |
+ :echo map([1, 2, 3], lambda("return a:1 + 1")) | |
+ :echo sort([3,7,2,1,4], lambda("return a:1 - a:2")) | |
+ | |
+ Lambda function is possible to reference the variables in the | |
+ defined scope. | |
+ Example: | |
+ :let s:x = 2 | |
+ :echo filter([1, 2, 3], lambda("return a:1 >= s:x")) | |
+ | |
+ :function! Foo() | |
+ : let x = 1 | |
+ : return lambda("return x") | |
+ :endfunction | |
+ :echo Foo()() | |
+ | |
+ And if let new variable, it will be stored in the lambda's | |
+ scope. | |
+ Example: | |
+ :function! Foo() | |
+ : call lambda("let x = 1")() | |
+ : echo x | " Should be error | |
+ :endfunction | |
+ | |
+ For example, you can create counter generator. | |
+ | |
+ function! s:counter(x) | |
+ let x = a:x | |
+ return lambda(" | |
+ \ let x += 1 \n | |
+ \ return x | |
+ \") | |
+ endfunction | |
+ | |
+ let F = s:counter(0) | |
+ echo F() | " 1 | |
+ echo F() | " 2 | |
+ echo F() | " 3 | |
+ echo F() | " 4 | |
+ | |
*libcall()* *E364* *E368* | |
libcall({libname}, {funcname}, {argument}) | |
Call function {funcname} in the run-time library {libname} | |
@@ -4184,18 +4244,19 @@ | |
See |lua-luaeval| for more details. | |
{only available when compiled with the |+lua| feature} | |
-map({expr}, {string}) *map()* | |
- {expr} must be a |List| or a |Dictionary|. | |
- Replace each item in {expr} with the result of evaluating | |
- {string}. | |
- Inside {string} |v:val| has the value of the current item. | |
+map({expr1}, {expr2}) *map()* | |
+ {expr1} must be a |List| or a |Dictionary|. | |
+ Replace each item in {expr1} with the result of evaluating | |
+ {expr2}. | |
+ {expr2} must be a |string| or |Funcref|. If it's |string|, | |
+ inside {expr2} |v:val| has the value of the current item. | |
For a |Dictionary| |v:key| has the key of the current item | |
and for a |List| |v:key| has the index of the current item. | |
Example: > | |
:call map(mylist, '"> " . v:val . " <"') | |
< This puts "> " before and " <" after each item in "mylist". | |
- Note that {string} is the result of an expression and is then | |
+ Note that {expr2} is the result of an expression and is then | |
used as an expression again. Often it is good to use a | |
|literal-string| to avoid having to double backslashes. You | |
still have to double ' quotes | |
@@ -4204,9 +4265,12 @@ | |
|Dictionary| to remain unmodified make a copy first: > | |
:let tlist = map(copy(mylist), ' v:val . "\t"') | |
-< Returns {expr}, the |List| or |Dictionary| that was filtered. | |
- When an error is encountered while evaluating {string} no | |
- further items in {expr} are processed. | |
+< Returns {expr1}, the |List| or |Dictionary| that was filtered. | |
+ When an error is encountered while evaluating {expr2} no | |
+ further items in {expr1} are processed. | |
+ | |
+ {expr2} is possible to be given as |Funcref|. The function | |
+ should return value proceeded from "a:1". | |
maparg({name}[, {mode} [, {abbr} [, {dict}]]]) *maparg()* | |
diff -r 1b74025a66e7 src/Makefile | |
--- a/src/Makefile Sat Sep 27 11:18:20 2014 +0200 | |
+++ b/src/Makefile Sun Sep 28 23:39:50 2014 +0900 | |
@@ -1898,6 +1898,7 @@ | |
test_listlbr_utf8 \ | |
test_options \ | |
test_qf_title \ | |
+ test_lambda \ | |
test10 test11 test12 test13 test14 test15 test16 test17 test18 test19 \ | |
test20 test21 test22 test23 test24 test25 test26 test27 test28 test29 \ | |
test30 test31 test32 test33 test34 test35 test36 test37 test38 test39 \ | |
diff -r 1b74025a66e7 src/eval.c | |
--- a/src/eval.c Sat Sep 27 11:18:20 2014 +0200 | |
+++ b/src/eval.c Sun Sep 28 23:39:50 2014 +0900 | |
@@ -166,6 +166,7 @@ | |
* Structure to hold info for a user function. | |
*/ | |
typedef struct ufunc ufunc_T; | |
+typedef struct funccall_S funccall_T; | |
struct ufunc | |
{ | |
@@ -194,6 +195,7 @@ | |
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 function variables */ | |
char_u uf_name[1]; /* name of function (actually longer); can | |
start with <SNR>123_ (<SNR> is K_SPECIAL | |
KS_EXTRA KE_SNR) */ | |
@@ -230,8 +232,6 @@ | |
#define FIXVAR_CNT 12 /* number of fixed variables */ | |
/* structure to hold info for a function that is currently being executed. */ | |
-typedef struct funccall_S funccall_T; | |
- | |
struct funccall_S | |
{ | |
ufunc_T *func; /* function being called */ | |
@@ -256,6 +256,10 @@ | |
proftime_T prof_child; /* time spent in a child */ | |
#endif | |
funccall_T *caller; /* calling function or NULL */ | |
+ | |
+ /* for lambda */ | |
+ int ref_by_lambda; | |
+ int lambda_copyID; /* for garbage collection */ | |
}; | |
/* | |
@@ -603,6 +607,7 @@ | |
static void f_items __ARGS((typval_T *argvars, typval_T *rettv)); | |
static void f_join __ARGS((typval_T *argvars, typval_T *rettv)); | |
static void f_keys __ARGS((typval_T *argvars, typval_T *rettv)); | |
+static void f_lambda __ARGS((typval_T *argvars, typval_T *rettv)); | |
static void f_last_buffer_nr __ARGS((typval_T *argvars, typval_T *rettv)); | |
static void f_len __ARGS((typval_T *argvars, typval_T *rettv)); | |
static void f_libcall __ARGS((typval_T *argvars, typval_T *rettv)); | |
@@ -3710,11 +3715,32 @@ | |
hashitem_T *hi; | |
char_u *varname; | |
dictitem_T *di; | |
+ funccall_T *old_current_funccal; | |
ht = find_var_ht(name, &varname); | |
if (ht != NULL && *varname != NUL) | |
{ | |
hi = hash_find(ht, varname); | |
+ | |
+ if (HASHITEM_EMPTY(hi) && current_funccal != NULL && | |
+ current_funccal->func->uf_scoped != NULL) | |
+ { | |
+ /* Search in parent scope for lambda */ | |
+ old_current_funccal = current_funccal; | |
+ current_funccal = current_funccal->func->uf_scoped; | |
+ while (current_funccal) | |
+ { | |
+ ht = find_var_ht(name, &varname); | |
+ if (ht != NULL && *varname != NUL) | |
+ { | |
+ hi = hash_find(ht, varname); | |
+ if (!HASHITEM_EMPTY(hi)) | |
+ break; | |
+ } | |
+ current_funccal = current_funccal->func->uf_scoped; | |
+ } | |
+ current_funccal = old_current_funccal; | |
+ } | |
if (!HASHITEM_EMPTY(hi)) | |
{ | |
di = HI2DI(hi); | |
@@ -6840,6 +6866,7 @@ | |
* the item is referenced elsewhere the funccal must not be freed. */ | |
for (fc = previous_funccal; fc != NULL; fc = fc->caller) | |
{ | |
+ fc->lambda_copyID = copyID + 1; | |
set_ref_in_ht(&fc->l_vars.dv_hashtab, copyID + 1); | |
set_ref_in_ht(&fc->l_avars.dv_hashtab, copyID + 1); | |
} | |
@@ -6912,6 +6939,7 @@ | |
else | |
pfc = &(*pfc)->caller; | |
} | |
+ | |
if (did_free_funccal) | |
/* When a funccal was freed some more items might be garbage | |
* collected, so run again. */ | |
@@ -7017,6 +7045,8 @@ | |
{ | |
dict_T *dd; | |
list_T *ll; | |
+ ufunc_T *fp; | |
+ funccall_T *fc; | |
switch (tv->v_type) | |
{ | |
@@ -7039,6 +7069,21 @@ | |
set_ref_in_list(ll, copyID); | |
} | |
break; | |
+ case VAR_FUNC: | |
+ fp = find_func(tv->vval.v_string); | |
+ if (fp != NULL) | |
+ { | |
+ for (fc = fp->uf_scoped; fc != NULL; fc = fc->func->uf_scoped) | |
+ { | |
+ if (fc->lambda_copyID != copyID) | |
+ { | |
+ fc->lambda_copyID = copyID; | |
+ set_ref_in_ht(&fc->l_vars.dv_hashtab, copyID); | |
+ set_ref_in_ht(&fc->l_avars.dv_hashtab, copyID); | |
+ } | |
+ } | |
+ } | |
+ break; | |
} | |
return; | |
} | |
@@ -8065,6 +8110,7 @@ | |
{"items", 1, 1, f_items}, | |
{"join", 1, 2, f_join}, | |
{"keys", 1, 1, f_keys}, | |
+ {"lambda", 1, 1, f_lambda}, | |
{"last_buffer_nr", 0, 0, f_last_buffer_nr},/* obsolete */ | |
{"len", 1, 1, f_len}, | |
{"libcall", 3, 3, f_libcall}, | |
@@ -8549,7 +8595,7 @@ | |
rettv->vval.v_number = 0; | |
error = ERROR_UNKNOWN; | |
- if (!builtin_function(rfname, -1)) | |
+ if (!builtin_function(rfname, -1) || !STRNICMP(rfname, "<LAMBDA>", 8)) | |
{ | |
/* | |
* User defined function. | |
@@ -10647,7 +10693,7 @@ | |
} | |
static void filter_map __ARGS((typval_T *argvars, typval_T *rettv, int map)); | |
-static int filter_map_one __ARGS((typval_T *tv, char_u *expr, int map, int *remp)); | |
+static int filter_map_one __ARGS((typval_T *tv, typval_T *expr, int map, int *remp)); | |
/* | |
* Implementation of map() and filter(). | |
@@ -10658,8 +10704,7 @@ | |
typval_T *rettv; | |
int map; | |
{ | |
- char_u buf[NUMBUFLEN]; | |
- char_u *expr; | |
+ typval_T *expr; | |
listitem_T *li, *nli; | |
list_T *l = NULL; | |
dictitem_T *di; | |
@@ -10694,14 +10739,13 @@ | |
return; | |
} | |
- expr = get_tv_string_buf_chk(&argvars[1], buf); | |
+ expr = &argvars[1]; | |
/* On type errors, the preceding call has already displayed an error | |
* message. Avoid a misleading error message for an empty string that | |
* was not passed as argument. */ | |
- if (expr != NULL) | |
+ if (expr->v_type != VAR_UNKNOWN) | |
{ | |
prepare_vimvar(VV_VAL, &save_val); | |
- expr = skipwhite(expr); | |
/* We reset "did_emsg" to be able to detect whether an error | |
* occurred during evaluation of the expression. */ | |
@@ -10767,22 +10811,32 @@ | |
static int | |
filter_map_one(tv, expr, map, remp) | |
typval_T *tv; | |
- char_u *expr; | |
+ typval_T *expr; | |
int map; | |
int *remp; | |
{ | |
typval_T rettv; | |
+ int retval = FAIL; | |
+ int dummy; | |
char_u *s; | |
- int retval = FAIL; | |
copy_tv(tv, &vimvars[VV_VAL].vv_tv); | |
- s = expr; | |
- if (eval1(&s, &rettv, TRUE) == FAIL) | |
+ s = expr->vval.v_string; | |
+ if (expr->v_type == VAR_FUNC) | |
+ { | |
+ if (call_func(s, (int)STRLEN(s), | |
+ &rettv, 1, tv, 0L, 0L, &dummy, TRUE, NULL) == FALSE) | |
goto theend; | |
- if (*s != NUL) /* check for trailing chars after expr */ | |
- { | |
- EMSG2(_(e_invexpr2), s); | |
- goto theend; | |
+ } | |
+ else { | |
+ s = skipwhite(s); | |
+ if (eval1(&s, &rettv, TRUE) == FAIL) | |
+ goto theend; | |
+ if (*s != NUL) /* check for trailing chars after expr */ | |
+ { | |
+ EMSG2(_(e_invexpr2), s); | |
+ goto theend; | |
+ } | |
} | |
if (map) | |
{ | |
@@ -13817,6 +13871,83 @@ | |
} | |
/* | |
+ * "lambda()" function. | |
+ */ | |
+ static void | |
+f_lambda(argvars, rettv) | |
+ typval_T *argvars UNUSED; | |
+ typval_T *rettv; | |
+{ | |
+ char_u *s, *e; | |
+ garray_T newargs; | |
+ garray_T newlines; | |
+ ufunc_T *fp; | |
+ char_u name[20]; | |
+ static int lambda_no = 0; | |
+ funccall_T *fc; | |
+ | |
+ if (check_secure()) | |
+ return; | |
+ | |
+ s = get_tv_string_chk(&argvars[0]); | |
+ if (s == NULL) | |
+ goto erret; | |
+ | |
+ fp = (ufunc_T *)alloc((unsigned)(sizeof(ufunc_T) + 20)); | |
+ if (fp == NULL) | |
+ goto erret; | |
+ | |
+ sprintf(name, "<LAMBDA>%d", ++lambda_no); | |
+ rettv->vval.v_string = vim_strsave(name); | |
+ | |
+ ga_init2(&newargs, (int)sizeof(char_u *), 1); | |
+ ga_init2(&newlines, (int)sizeof(char_u *), 1); | |
+ | |
+ while (*s) | |
+ { | |
+ s = skipwhite(s); | |
+ e = s; | |
+ while (*e && *e != '\n') | |
+ e++; | |
+ if (ga_grow(&newlines, 1) == FAIL) | |
+ goto erret; | |
+ ((char_u **)(newlines.ga_data))[newlines.ga_len++] = vim_strnsave(s, e - s); | |
+ s = *e == 0 ? e : e + 1; | |
+ } | |
+ | |
+ fp->uf_refcount = 1; | |
+ STRCPY(fp->uf_name, name); | |
+ hash_add(&func_hashtab, UF2HIKEY(fp)); | |
+ fp->uf_args = newargs; | |
+ fp->uf_lines = newlines; | |
+#ifdef FEAT_PROFILE | |
+ fp->uf_tml_count = NULL; | |
+ fp->uf_tml_total = NULL; | |
+ fp->uf_tml_self = NULL; | |
+ fp->uf_profiling = FALSE; | |
+ if (prof_def_func()) | |
+ func_do_profile(fp); | |
+#endif | |
+ fp->uf_varargs = TRUE; | |
+ fp->uf_flags = 0; | |
+ fp->uf_calls = 0; | |
+ fp->uf_script_ID = current_SID; | |
+ if (current_funccal) | |
+ { | |
+ fp->uf_scoped = current_funccal; | |
+ current_funccal->ref_by_lambda = TRUE; | |
+ } | |
+ else | |
+ fp->uf_scoped = NULL; | |
+ rettv->v_type = VAR_FUNC; | |
+ return; | |
+ | |
+erret: | |
+ ga_clear_strings(&newargs); | |
+ ga_clear_strings(&newlines); | |
+} | |
+ | |
+/* | |
* "last_buffer_nr()" function. | |
*/ | |
static void | |
@@ -20880,6 +21011,37 @@ | |
return NULL; | |
} | |
+ | |
+ static dictitem_T* | |
+find_var_in_scoped_ht(name, varname, no_autoload) | |
+ char_u *name; | |
+ char_u **varname; | |
+ int no_autoload; | |
+{ | |
+ dictitem_T *v = NULL; | |
+ funccall_T *old_current_funccal = current_funccal; | |
+ hashtab_T *ht; | |
+ | |
+ /* Search in parent scope which is possible to reference from lambda */ | |
+ current_funccal = current_funccal->func->uf_scoped; | |
+ while (current_funccal) | |
+ { | |
+ ht = find_var_ht(name, varname ? &(*varname) : NULL); | |
+ if (ht != NULL) | |
+ { | |
+ v = find_var_in_ht(ht, *name, | |
+ varname ? *varname : NULL, no_autoload); | |
+ if (v != NULL) | |
+ break; | |
+ } | |
+ current_funccal = current_funccal->func->uf_scoped; | |
+ } | |
+ current_funccal = old_current_funccal; | |
+ | |
+ return v; | |
+} | |
+ | |
+ | |
/* | |
* Find variable "name" in the list of variables. | |
* Return a pointer to it if found, NULL if not found. | |
@@ -20895,13 +21057,23 @@ | |
{ | |
char_u *varname; | |
hashtab_T *ht; | |
+ dictitem_T *ret = NULL; | |
ht = find_var_ht(name, &varname); | |
if (htp != NULL) | |
*htp = ht; | |
if (ht == NULL) | |
return NULL; | |
- return find_var_in_ht(ht, *name, varname, no_autoload || htp != NULL); | |
+ ret = find_var_in_ht(ht, *name, varname, no_autoload || htp != NULL); | |
+ if (ret != NULL) | |
+ return ret; | |
+ | |
+ /* Search in parent scope for lambda */ | |
+ if (current_funccal != NULL && current_funccal->func->uf_scoped != NULL) | |
+ return find_var_in_scoped_ht(name, varname ? &varname : NULL, | |
+ no_autoload || htp != NULL); | |
+ | |
+ return NULL; | |
} | |
/* | |
@@ -21252,6 +21424,24 @@ | |
} | |
v = find_var_in_ht(ht, 0, varname, TRUE); | |
+ /* Search in parent scope which is possible to reference from lambda */ | |
+ if (v == NULL && current_funccal != NULL && | |
+ current_funccal->func->uf_scoped != NULL) | |
+ { | |
+ v = find_var_in_scoped_ht(name, varname ? &varname : NULL, TRUE); | |
+ | |
+ /* When the variable is not found, let scope should be parent of the | |
+ * lambda. | |
+ */ | |
+ if (v == NULL) | |
+ { | |
+ hashtab_T *ht_tmp; | |
+ ht_tmp = find_var_ht(name, &varname); | |
+ if (ht_tmp != NULL) | |
+ ht = ht_tmp; | |
+ } | |
+ } | |
+ | |
if (tv->v_type == VAR_FUNC && var_check_func_name(name, v == NULL)) | |
return; | |
@@ -22498,6 +22688,7 @@ | |
fp->uf_flags = flags; | |
fp->uf_calls = 0; | |
fp->uf_script_ID = current_SID; | |
+ fp->uf_scoped = NULL; | |
goto ret_free; | |
erret: | |
@@ -23329,7 +23520,9 @@ | |
{ | |
ufunc_T *fp; | |
- if (name != NULL && isdigit(*name)) | |
+ if (name == NULL) | |
+ return; | |
+ else if (isdigit(*name)) | |
{ | |
fp = find_func(name); | |
if (fp == NULL) | |
@@ -23342,6 +23535,18 @@ | |
func_free(fp); | |
} | |
} | |
+ else if (!STRNICMP(name, "<LAMBDA>", 8)) | |
+ { | |
+ /* 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 | |
+ * when "uf_calls" becomes zero. */ | |
+ if (fp->uf_calls == 0) | |
+ func_free(fp); | |
+ } | |
+ } | |
} | |
/* | |
@@ -23353,7 +23558,9 @@ | |
{ | |
ufunc_T *fp; | |
- if (name != NULL && isdigit(*name)) | |
+ if (name == NULL) | |
+ return; | |
+ else if (isdigit(*name)) | |
{ | |
fp = find_func(name); | |
if (fp == NULL) | |
@@ -23361,6 +23568,13 @@ | |
else | |
++fp->uf_refcount; | |
} | |
+ else if (!STRNICMP(name, "<LAMBDA>", 8)) | |
+ { | |
+ /* fail silently, when lambda function isn't be found. */ | |
+ fp = find_func(name); | |
+ if (fp != NULL) | |
+ ++fp->uf_refcount; | |
+ } | |
} | |
/* | |
@@ -23417,6 +23631,9 @@ | |
/* Check if this function has a breakpoint. */ | |
fc->breakpoint = dbg_find_breakpoint(FALSE, fp->uf_name, (linenr_T)0); | |
fc->dbg_tick = debug_tick; | |
+ /* Set up fields for lambda. */ | |
+ fc->ref_by_lambda = FALSE; | |
+ fc->lambda_copyID = current_copyID; | |
/* | |
* Note about using fc->fixvar[]: This is an array of FIXVAR_CNT variables | |
@@ -23697,7 +23914,8 @@ | |
* free the funccall_T and what's in it. */ | |
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) | |
+ && fc->l_avars.dv_refcount == DO_NOT_FREE_CNT | |
+ && !fc->ref_by_lambda) | |
{ | |
free_funccal(fc, FALSE); | |
} | |
@@ -23742,7 +23960,8 @@ | |
{ | |
return (fc->l_varlist.lv_copyID != copyID | |
&& fc->l_vars.dv_copyID != copyID | |
- && fc->l_avars.dv_copyID != copyID); | |
+ && fc->l_avars.dv_copyID != copyID | |
+ && fc->lambda_copyID != copyID); | |
} | |
/* |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
👍