@@ -59,6 +59,7 @@ struct ufunc
5959#define FC_ABORT 1 /* abort function on error */
6060#define FC_RANGE 2 /* function accepts range */
6161#define FC_DICT 4 /* Dict function, uses "self" */
62+ #define FC_CLOSURE 8 /* closure, uses outer scope variables */
6263
6364/* From user function to hashitem and back. */
6465#define UF2HIKEY (fp ) ((fp)->uf_name)
@@ -312,7 +313,7 @@ get_lambda_tv(char_u **arg, typval_T *rettv, int evaluate)
312313
313314 if (evaluate )
314315 {
315- int len ;
316+ int len , flags = 0 ;
316317 char_u * p ;
317318
318319 sprintf ((char * )name , "<lambda>%d" , ++ lambda_no );
@@ -341,6 +342,7 @@ get_lambda_tv(char_u **arg, typval_T *rettv, int evaluate)
341342 fp -> uf_lines = newlines ;
342343 if (current_funccal != NULL && eval_lavars )
343344 {
345+ flags |= FC_CLOSURE ;
344346 fp -> uf_scoped = current_funccal ;
345347 current_funccal -> fc_refcount ++ ;
346348 if (ga_grow (& current_funccal -> fc_funcs , 1 ) == FAIL )
@@ -361,7 +363,7 @@ get_lambda_tv(char_u **arg, typval_T *rettv, int evaluate)
361363 func_do_profile (fp );
362364#endif
363365 fp -> uf_varargs = TRUE;
364- fp -> uf_flags = 0 ;
366+ fp -> uf_flags = flags ;
365367 fp -> uf_calls = 0 ;
366368 fp -> uf_script_ID = current_SID ;
367369
@@ -1487,6 +1489,8 @@ list_func_head(ufunc_T *fp, int indent)
14871489 MSG_PUTS (" range" );
14881490 if (fp -> uf_flags & FC_DICT )
14891491 MSG_PUTS (" dict" );
1492+ if (fp -> uf_flags & FC_CLOSURE )
1493+ MSG_PUTS (" closure" );
14901494 msg_clr_eos ();
14911495 if (p_verbose > 0 )
14921496 last_set_msg (fp -> uf_script_ID );
@@ -1948,7 +1952,7 @@ ex_function(exarg_T *eap)
19481952 if (get_function_args (& p , ')' , & newargs , & varargs , eap -> skip ) == FAIL )
19491953 goto errret_2 ;
19501954
1951- /* find extra arguments "range", "dict" and "abort " */
1955+ /* find extra arguments "range", "dict", "abort" and "closure " */
19521956 for (;;)
19531957 {
19541958 p = skipwhite (p );
@@ -1967,6 +1971,11 @@ ex_function(exarg_T *eap)
19671971 flags |= FC_ABORT ;
19681972 p += 5 ;
19691973 }
1974+ else if (STRNCMP (p , "closure" , 7 ) == 0 )
1975+ {
1976+ flags |= FC_CLOSURE ;
1977+ p += 7 ;
1978+ }
19701979 else
19711980 break ;
19721981 }
@@ -2299,7 +2308,25 @@ ex_function(exarg_T *eap)
22992308 }
23002309 fp -> uf_args = newargs ;
23012310 fp -> uf_lines = newlines ;
2302- fp -> uf_scoped = NULL ;
2311+ if ((flags & FC_CLOSURE ) != 0 )
2312+ {
2313+ if (current_funccal == NULL )
2314+ {
2315+ emsg_funcname (N_ ("E932 Closure function should not be at top level: %s" ),
2316+ name );
2317+ goto erret ;
2318+ }
2319+ fp -> uf_scoped = current_funccal ;
2320+ current_funccal -> fc_refcount ++ ;
2321+ if (ga_grow (& current_funccal -> fc_funcs , 1 ) == FAIL )
2322+ goto erret ;
2323+ ((ufunc_T * * )current_funccal -> fc_funcs .ga_data )
2324+ [current_funccal -> fc_funcs .ga_len ++ ] = fp ;
2325+ func_ref (current_funccal -> func -> uf_name );
2326+ }
2327+ else
2328+ fp -> uf_scoped = NULL ;
2329+
23032330#ifdef FEAT_PROFILE
23042331 fp -> uf_tml_count = NULL ;
23052332 fp -> uf_tml_total = NULL ;
@@ -3535,6 +3562,42 @@ get_current_funccal_dict(hashtab_T *ht)
35353562 return NULL ;
35363563}
35373564
3565+ /*
3566+ * Search hashitem in parent scope.
3567+ */
3568+ hashitem_T *
3569+ find_hi_in_scoped_ht (char_u * name , char_u * * varname , hashtab_T * * pht )
3570+ {
3571+ funccall_T * old_current_funccal = current_funccal ;
3572+ hashtab_T * ht ;
3573+ hashitem_T * hi = NULL ;
3574+
3575+ if (current_funccal == NULL || current_funccal -> func -> uf_scoped == NULL )
3576+ return NULL ;
3577+
3578+ /* Search in parent scope which is possible to reference from lambda */
3579+ current_funccal = current_funccal -> func -> uf_scoped ;
3580+ while (current_funccal )
3581+ {
3582+ ht = find_var_ht (name , varname );
3583+ if (ht != NULL && * * varname != NUL )
3584+ {
3585+ hi = hash_find (ht , * varname );
3586+ if (!HASHITEM_EMPTY (hi ))
3587+ {
3588+ * pht = ht ;
3589+ break ;
3590+ }
3591+ }
3592+ if (current_funccal == current_funccal -> func -> uf_scoped )
3593+ break ;
3594+ current_funccal = current_funccal -> func -> uf_scoped ;
3595+ }
3596+ current_funccal = old_current_funccal ;
3597+
3598+ return hi ;
3599+ }
3600+
35383601/*
35393602 * Search variable in parent scope.
35403603 */
0 commit comments