Mercurial > vim
comparison src/userfunc.c @ 9686:8c2553beff0f v7.4.2119
commit https://github.com/vim/vim/commit/1e96d9bf98f9ab84d5af7f98d6a961d91b17364f
Author: Bram Moolenaar <Bram@vim.org>
Date: Fri Jul 29 22:15:09 2016 +0200
patch 7.4.2119
Problem: Closures are not supported.
Solution: Capture variables in lambdas from the outer scope. (Yasuhiro
Matsumoto, Ken Takata)
author | Christian Brabandt <cb@256bit.org> |
---|---|
date | Fri, 29 Jul 2016 22:30:08 +0200 |
parents | f1920505bc16 |
children | 2ea935bdd1a1 |
comparison
equal
deleted
inserted
replaced
9685:fee40b9f4989 | 9686:8c2553beff0f |
---|---|
12 */ | 12 */ |
13 | 13 |
14 #include "vim.h" | 14 #include "vim.h" |
15 | 15 |
16 #if defined(FEAT_EVAL) || defined(PROTO) | 16 #if defined(FEAT_EVAL) || defined(PROTO) |
17 | |
18 typedef struct funccall_S funccall_T; | |
17 | 19 |
18 /* | 20 /* |
19 * Structure to hold info for a user function. | 21 * Structure to hold info for a user function. |
20 */ | 22 */ |
21 typedef struct ufunc ufunc_T; | 23 typedef struct ufunc ufunc_T; |
45 int uf_tml_execed; /* line being timed was executed */ | 47 int uf_tml_execed; /* line being timed was executed */ |
46 #endif | 48 #endif |
47 scid_T uf_script_ID; /* ID of script where function was defined, | 49 scid_T uf_script_ID; /* ID of script where function was defined, |
48 used for s: variables */ | 50 used for s: variables */ |
49 int uf_refcount; /* for numbered function: reference count */ | 51 int uf_refcount; /* for numbered function: reference count */ |
52 funccall_T *uf_scoped; /* l: local variables for closure */ | |
50 char_u uf_name[1]; /* name of function (actually longer); can | 53 char_u uf_name[1]; /* name of function (actually longer); can |
51 start with <SNR>123_ (<SNR> is K_SPECIAL | 54 start with <SNR>123_ (<SNR> is K_SPECIAL |
52 KS_EXTRA KE_SNR) */ | 55 KS_EXTRA KE_SNR) */ |
53 }; | 56 }; |
54 | 57 |
68 #define MAX_FUNC_ARGS 20 /* maximum number of function arguments */ | 71 #define MAX_FUNC_ARGS 20 /* maximum number of function arguments */ |
69 #define VAR_SHORT_LEN 20 /* short variable name length */ | 72 #define VAR_SHORT_LEN 20 /* short variable name length */ |
70 #define FIXVAR_CNT 12 /* number of fixed variables */ | 73 #define FIXVAR_CNT 12 /* number of fixed variables */ |
71 | 74 |
72 /* structure to hold info for a function that is currently being executed. */ | 75 /* structure to hold info for a function that is currently being executed. */ |
73 typedef struct funccall_S funccall_T; | |
74 | |
75 struct funccall_S | 76 struct funccall_S |
76 { | 77 { |
77 ufunc_T *func; /* function being called */ | 78 ufunc_T *func; /* function being called */ |
78 int linenr; /* next line to be executed */ | 79 int linenr; /* next line to be executed */ |
79 int returned; /* ":return" used */ | 80 int returned; /* ":return" used */ |
94 int level; /* top nesting level of executed function */ | 95 int level; /* top nesting level of executed function */ |
95 #ifdef FEAT_PROFILE | 96 #ifdef FEAT_PROFILE |
96 proftime_T prof_child; /* time spent in a child */ | 97 proftime_T prof_child; /* time spent in a child */ |
97 #endif | 98 #endif |
98 funccall_T *caller; /* calling function or NULL */ | 99 funccall_T *caller; /* calling function or NULL */ |
100 | |
101 /* for closure */ | |
102 int fc_refcount; | |
103 int fc_copyID; /* for garbage collection */ | |
104 garray_T fc_funcs; /* list of ufunc_T* which refer this */ | |
99 }; | 105 }; |
100 | 106 |
101 /* | 107 /* |
102 * Struct used by trans_function_name() | 108 * Struct used by trans_function_name() |
103 */ | 109 */ |
257 int | 263 int |
258 get_lambda_tv(char_u **arg, typval_T *rettv, int evaluate) | 264 get_lambda_tv(char_u **arg, typval_T *rettv, int evaluate) |
259 { | 265 { |
260 garray_T newargs; | 266 garray_T newargs; |
261 garray_T newlines; | 267 garray_T newlines; |
268 garray_T *pnewargs; | |
262 ufunc_T *fp = NULL; | 269 ufunc_T *fp = NULL; |
263 int varargs; | 270 int varargs; |
264 int ret; | 271 int ret; |
265 char_u name[20]; | 272 char_u name[20]; |
266 char_u *start = skipwhite(*arg + 1); | 273 char_u *start = skipwhite(*arg + 1); |
267 char_u *s, *e; | 274 char_u *s, *e; |
268 static int lambda_no = 0; | 275 static int lambda_no = 0; |
276 int *old_eval_lavars = eval_lavars_used; | |
277 int eval_lavars = FALSE; | |
269 | 278 |
270 ga_init(&newargs); | 279 ga_init(&newargs); |
271 ga_init(&newlines); | 280 ga_init(&newlines); |
272 | 281 |
273 /* First, check if this is a lambda expression. "->" must exist. */ | 282 /* First, check if this is a lambda expression. "->" must exist. */ |
274 ret = get_function_args(&start, '-', NULL, NULL, TRUE); | 283 ret = get_function_args(&start, '-', NULL, NULL, TRUE); |
275 if (ret == FAIL || *start != '>') | 284 if (ret == FAIL || *start != '>') |
276 return NOTDONE; | 285 return NOTDONE; |
277 | 286 |
278 /* Parse the arguments again. */ | 287 /* Parse the arguments again. */ |
288 if (evaluate) | |
289 pnewargs = &newargs; | |
290 else | |
291 pnewargs = NULL; | |
279 *arg = skipwhite(*arg + 1); | 292 *arg = skipwhite(*arg + 1); |
280 ret = get_function_args(arg, '-', &newargs, &varargs, FALSE); | 293 ret = get_function_args(arg, '-', pnewargs, &varargs, FALSE); |
281 if (ret == FAIL || **arg != '>') | 294 if (ret == FAIL || **arg != '>') |
282 goto errret; | 295 goto errret; |
296 | |
297 /* Set up dictionaries for checking local variables and arguments. */ | |
298 if (evaluate) | |
299 eval_lavars_used = &eval_lavars; | |
283 | 300 |
284 /* Get the start and the end of the expression. */ | 301 /* Get the start and the end of the expression. */ |
285 *arg = skipwhite(*arg + 1); | 302 *arg = skipwhite(*arg + 1); |
286 s = *arg; | 303 s = *arg; |
287 ret = skip_expr(arg); | 304 ret = skip_expr(arg); |
296 if (evaluate) | 313 if (evaluate) |
297 { | 314 { |
298 int len; | 315 int len; |
299 char_u *p; | 316 char_u *p; |
300 | 317 |
301 fp = (ufunc_T *)alloc((unsigned)(sizeof(ufunc_T) + 20)); | 318 sprintf((char*)name, "<lambda>%d", ++lambda_no); |
319 | |
320 fp = (ufunc_T *)alloc((unsigned)(sizeof(ufunc_T) + STRLEN(name))); | |
302 if (fp == NULL) | 321 if (fp == NULL) |
303 goto errret; | 322 goto errret; |
304 | |
305 sprintf((char*)name, "<lambda>%d", ++lambda_no); | |
306 | 323 |
307 ga_init2(&newlines, (int)sizeof(char_u *), 1); | 324 ga_init2(&newlines, (int)sizeof(char_u *), 1); |
308 if (ga_grow(&newlines, 1) == FAIL) | 325 if (ga_grow(&newlines, 1) == FAIL) |
309 goto errret; | 326 goto errret; |
310 | 327 |
311 /* Add "return " before the expression. | 328 /* Add "return " before the expression. */ |
312 * TODO: Support multiple expressions. */ | |
313 len = 7 + e - s + 1; | 329 len = 7 + e - s + 1; |
314 p = (char_u *)alloc(len); | 330 p = (char_u *)alloc(len); |
315 if (p == NULL) | 331 if (p == NULL) |
316 goto errret; | 332 goto errret; |
317 ((char_u **)(newlines.ga_data))[newlines.ga_len++] = p; | 333 ((char_u **)(newlines.ga_data))[newlines.ga_len++] = p; |
318 STRCPY(p, "return "); | 334 STRCPY(p, "return "); |
319 STRNCPY(p + 7, s, e - s); | 335 vim_strncpy(p + 7, s, e - s); |
320 p[7 + e - s] = NUL; | |
321 | 336 |
322 fp->uf_refcount = 1; | 337 fp->uf_refcount = 1; |
323 STRCPY(fp->uf_name, name); | 338 STRCPY(fp->uf_name, name); |
324 hash_add(&func_hashtab, UF2HIKEY(fp)); | 339 hash_add(&func_hashtab, UF2HIKEY(fp)); |
325 fp->uf_args = newargs; | 340 fp->uf_args = newargs; |
326 fp->uf_lines = newlines; | 341 fp->uf_lines = newlines; |
342 if (current_funccal != NULL && eval_lavars) | |
343 { | |
344 fp->uf_scoped = current_funccal; | |
345 current_funccal->fc_refcount++; | |
346 if (ga_grow(¤t_funccal->fc_funcs, 1) == FAIL) | |
347 goto errret; | |
348 ((ufunc_T **)current_funccal->fc_funcs.ga_data) | |
349 [current_funccal->fc_funcs.ga_len++] = fp; | |
350 func_ref(current_funccal->func->uf_name); | |
351 } | |
352 else | |
353 fp->uf_scoped = NULL; | |
327 | 354 |
328 #ifdef FEAT_PROFILE | 355 #ifdef FEAT_PROFILE |
329 fp->uf_tml_count = NULL; | 356 fp->uf_tml_count = NULL; |
330 fp->uf_tml_total = NULL; | 357 fp->uf_tml_total = NULL; |
331 fp->uf_tml_self = NULL; | 358 fp->uf_tml_self = NULL; |
339 fp->uf_script_ID = current_SID; | 366 fp->uf_script_ID = current_SID; |
340 | 367 |
341 rettv->vval.v_string = vim_strsave(name); | 368 rettv->vval.v_string = vim_strsave(name); |
342 rettv->v_type = VAR_FUNC; | 369 rettv->v_type = VAR_FUNC; |
343 } | 370 } |
344 else | 371 |
345 ga_clear_strings(&newargs); | 372 eval_lavars_used = old_eval_lavars; |
346 | |
347 return OK; | 373 return OK; |
348 | 374 |
349 errret: | 375 errret: |
350 ga_clear_strings(&newargs); | 376 ga_clear_strings(&newargs); |
351 ga_clear_strings(&newlines); | 377 ga_clear_strings(&newlines); |
352 vim_free(fp); | 378 vim_free(fp); |
379 eval_lavars_used = old_eval_lavars; | |
353 return FAIL; | 380 return FAIL; |
354 } | 381 } |
355 | 382 |
356 /* | 383 /* |
357 * Check if "name" is a variable of type VAR_FUNC. If so, return the function | 384 * Check if "name" is a variable of type VAR_FUNC. If so, return the function |
622 free_funccal( | 649 free_funccal( |
623 funccall_T *fc, | 650 funccall_T *fc, |
624 int free_val) /* a: vars were allocated */ | 651 int free_val) /* a: vars were allocated */ |
625 { | 652 { |
626 listitem_T *li; | 653 listitem_T *li; |
654 int i; | |
655 | |
656 for (i = 0; i < fc->fc_funcs.ga_len; ++i) | |
657 { | |
658 ufunc_T *fp = ((ufunc_T **)(fc->fc_funcs.ga_data))[i]; | |
659 | |
660 if (fp != NULL) | |
661 fp->uf_scoped = NULL; | |
662 } | |
627 | 663 |
628 /* The a: variables typevals may not have been allocated, only free the | 664 /* The a: variables typevals may not have been allocated, only free the |
629 * allocated variables. */ | 665 * allocated variables. */ |
630 vars_clear_ext(&fc->l_avars.dv_hashtab, free_val); | 666 vars_clear_ext(&fc->l_avars.dv_hashtab, free_val); |
631 | 667 |
635 /* Free the a:000 variables if they were allocated. */ | 671 /* Free the a:000 variables if they were allocated. */ |
636 if (free_val) | 672 if (free_val) |
637 for (li = fc->l_varlist.lv_first; li != NULL; li = li->li_next) | 673 for (li = fc->l_varlist.lv_first; li != NULL; li = li->li_next) |
638 clear_tv(&li->li_tv); | 674 clear_tv(&li->li_tv); |
639 | 675 |
676 for (i = 0; i < fc->fc_funcs.ga_len; ++i) | |
677 { | |
678 ufunc_T *fp = ((ufunc_T **)(fc->fc_funcs.ga_data))[i]; | |
679 | |
680 if (fp != NULL) | |
681 func_unref(fc->func->uf_name); | |
682 } | |
683 ga_clear(&fc->fc_funcs); | |
684 | |
685 func_unref(fc->func->uf_name); | |
640 vim_free(fc); | 686 vim_free(fc); |
641 } | 687 } |
642 | 688 |
643 /* | 689 /* |
644 * Call a user function. | 690 * Call a user function. |
694 fc->returned = FALSE; | 740 fc->returned = FALSE; |
695 fc->level = ex_nesting_level; | 741 fc->level = ex_nesting_level; |
696 /* Check if this function has a breakpoint. */ | 742 /* Check if this function has a breakpoint. */ |
697 fc->breakpoint = dbg_find_breakpoint(FALSE, fp->uf_name, (linenr_T)0); | 743 fc->breakpoint = dbg_find_breakpoint(FALSE, fp->uf_name, (linenr_T)0); |
698 fc->dbg_tick = debug_tick; | 744 fc->dbg_tick = debug_tick; |
745 /* Set up fields for closure. */ | |
746 fc->fc_refcount = 0; | |
747 fc->fc_copyID = 0; | |
748 ga_init2(&fc->fc_funcs, sizeof(ufunc_T *), 1); | |
749 func_ref(fp->uf_name); | |
699 | 750 |
700 if (STRNCMP(fp->uf_name, "<lambda>", 8) == 0) | 751 if (STRNCMP(fp->uf_name, "<lambda>", 8) == 0) |
701 islambda = TRUE; | 752 islambda = TRUE; |
702 | 753 |
703 /* | 754 /* |
756 add_nr_var(&fc->l_avars, &fc->fixvar[fixvar_idx++].var, "lastline", | 807 add_nr_var(&fc->l_avars, &fc->fixvar[fixvar_idx++].var, "lastline", |
757 (varnumber_T)lastline); | 808 (varnumber_T)lastline); |
758 for (i = 0; i < argcount; ++i) | 809 for (i = 0; i < argcount; ++i) |
759 { | 810 { |
760 int addlocal = FALSE; | 811 int addlocal = FALSE; |
761 dictitem_T *v2; | |
762 | 812 |
763 ai = i - fp->uf_args.ga_len; | 813 ai = i - fp->uf_args.ga_len; |
764 if (ai < 0) | 814 if (ai < 0) |
765 { | 815 { |
766 /* named argument a:name */ | 816 /* named argument a:name */ |
776 } | 826 } |
777 if (fixvar_idx < FIXVAR_CNT && STRLEN(name) <= VAR_SHORT_LEN) | 827 if (fixvar_idx < FIXVAR_CNT && STRLEN(name) <= VAR_SHORT_LEN) |
778 { | 828 { |
779 v = &fc->fixvar[fixvar_idx++].var; | 829 v = &fc->fixvar[fixvar_idx++].var; |
780 v->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX; | 830 v->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX; |
781 | |
782 if (addlocal) | |
783 v2 = v; | |
784 } | 831 } |
785 else | 832 else |
786 { | 833 { |
787 v = (dictitem_T *)alloc((unsigned)(sizeof(dictitem_T) | 834 v = (dictitem_T *)alloc((unsigned)(sizeof(dictitem_T) |
788 + STRLEN(name))); | 835 + STRLEN(name))); |
789 if (v == NULL) | 836 if (v == NULL) |
790 break; | 837 break; |
791 v->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX | DI_FLAGS_ALLOC; | 838 v->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX | DI_FLAGS_ALLOC; |
792 | |
793 if (addlocal) | |
794 { | |
795 v2 = (dictitem_T *)alloc((unsigned)(sizeof(dictitem_T) | |
796 + STRLEN(name))); | |
797 if (v2 == NULL) | |
798 { | |
799 vim_free(v); | |
800 break; | |
801 } | |
802 v2->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX | DI_FLAGS_ALLOC; | |
803 } | |
804 } | 839 } |
805 STRCPY(v->di_key, name); | 840 STRCPY(v->di_key, name); |
806 hash_add(&fc->l_avars.dv_hashtab, DI2HIKEY(v)); | |
807 | 841 |
808 /* Note: the values are copied directly to avoid alloc/free. | 842 /* Note: the values are copied directly to avoid alloc/free. |
809 * "argvars" must have VAR_FIXED for v_lock. */ | 843 * "argvars" must have VAR_FIXED for v_lock. */ |
810 v->di_tv = argvars[i]; | 844 v->di_tv = argvars[i]; |
811 v->di_tv.v_lock = VAR_FIXED; | 845 v->di_tv.v_lock = VAR_FIXED; |
812 | 846 |
813 /* Named arguments can be accessed without the "a:" prefix in lambda | |
814 * expressions. Add to the l: dict. */ | |
815 if (addlocal) | 847 if (addlocal) |
816 { | 848 { |
817 STRCPY(v2->di_key, name); | 849 /* Named arguments should be accessed without the "a:" prefix in |
818 copy_tv(&v->di_tv, &v2->di_tv); | 850 * lambda expressions. Add to the l: dict. */ |
819 v2->di_tv.v_lock = VAR_FIXED; | 851 copy_tv(&v->di_tv, &v->di_tv); |
820 hash_add(&fc->l_vars.dv_hashtab, DI2HIKEY(v2)); | 852 hash_add(&fc->l_vars.dv_hashtab, DI2HIKEY(v)); |
821 } | 853 } |
854 else | |
855 hash_add(&fc->l_avars.dv_hashtab, DI2HIKEY(v)); | |
822 | 856 |
823 if (ai >= 0 && ai < MAX_FUNC_ARGS) | 857 if (ai >= 0 && ai < MAX_FUNC_ARGS) |
824 { | 858 { |
825 list_append(&fc->l_varlist, &fc->l_listitems[ai]); | 859 list_append(&fc->l_varlist, &fc->l_listitems[ai]); |
826 fc->l_listitems[ai].li_tv = argvars[i]; | 860 fc->l_listitems[ai].li_tv = argvars[i]; |
1012 | 1046 |
1013 /* If the a:000 list and the l: and a: dicts are not referenced we can | 1047 /* If the a:000 list and the l: and a: dicts are not referenced we can |
1014 * free the funccall_T and what's in it. */ | 1048 * free the funccall_T and what's in it. */ |
1015 if (fc->l_varlist.lv_refcount == DO_NOT_FREE_CNT | 1049 if (fc->l_varlist.lv_refcount == DO_NOT_FREE_CNT |
1016 && fc->l_vars.dv_refcount == DO_NOT_FREE_CNT | 1050 && fc->l_vars.dv_refcount == DO_NOT_FREE_CNT |
1017 && fc->l_avars.dv_refcount == DO_NOT_FREE_CNT) | 1051 && fc->l_avars.dv_refcount == DO_NOT_FREE_CNT |
1052 && fc->fc_refcount <= 0) | |
1018 { | 1053 { |
1019 free_funccal(fc, FALSE); | 1054 free_funccal(fc, FALSE); |
1020 } | 1055 } |
1021 else | 1056 else |
1022 { | 1057 { |
1043 } | 1078 } |
1044 | 1079 |
1045 /* Make a copy of the a:000 items, since we didn't do that above. */ | 1080 /* Make a copy of the a:000 items, since we didn't do that above. */ |
1046 for (li = fc->l_varlist.lv_first; li != NULL; li = li->li_next) | 1081 for (li = fc->l_varlist.lv_first; li != NULL; li = li->li_next) |
1047 copy_tv(&li->li_tv, &li->li_tv); | 1082 copy_tv(&li->li_tv, &li->li_tv); |
1083 } | |
1084 } | |
1085 | |
1086 /* | |
1087 * Unreference "fc": decrement the reference count and free it when it | |
1088 * becomes zero. If "fp" is not NULL, "fp" is detached from "fc". | |
1089 */ | |
1090 static void | |
1091 funccal_unref(funccall_T *fc, ufunc_T *fp) | |
1092 { | |
1093 funccall_T **pfc; | |
1094 int i; | |
1095 int freed = FALSE; | |
1096 | |
1097 if (fc == NULL) | |
1098 return; | |
1099 | |
1100 if (--fc->fc_refcount <= 0) | |
1101 { | |
1102 for (pfc = &previous_funccal; *pfc != NULL; ) | |
1103 { | |
1104 if (fc == *pfc | |
1105 && fc->l_varlist.lv_refcount == DO_NOT_FREE_CNT | |
1106 && fc->l_vars.dv_refcount == DO_NOT_FREE_CNT | |
1107 && fc->l_avars.dv_refcount == DO_NOT_FREE_CNT) | |
1108 { | |
1109 *pfc = fc->caller; | |
1110 free_funccal(fc, TRUE); | |
1111 freed = TRUE; | |
1112 } | |
1113 else | |
1114 pfc = &(*pfc)->caller; | |
1115 } | |
1116 } | |
1117 if (!freed) | |
1118 { | |
1119 func_unref(fc->func->uf_name); | |
1120 | |
1121 if (fp != NULL) | |
1122 { | |
1123 for (i = 0; i < fc->fc_funcs.ga_len; ++i) | |
1124 { | |
1125 if (((ufunc_T **)(fc->fc_funcs.ga_data))[i] == fp) | |
1126 ((ufunc_T **)(fc->fc_funcs.ga_data))[i] = NULL; | |
1127 } | |
1128 } | |
1048 } | 1129 } |
1049 } | 1130 } |
1050 | 1131 |
1051 /* | 1132 /* |
1052 * Free a function and remove it from the list of functions. | 1133 * Free a function and remove it from the list of functions. |
1069 hi = hash_find(&func_hashtab, UF2HIKEY(fp)); | 1150 hi = hash_find(&func_hashtab, UF2HIKEY(fp)); |
1070 if (HASHITEM_EMPTY(hi)) | 1151 if (HASHITEM_EMPTY(hi)) |
1071 EMSG2(_(e_intern2), "func_free()"); | 1152 EMSG2(_(e_intern2), "func_free()"); |
1072 else | 1153 else |
1073 hash_remove(&func_hashtab, hi); | 1154 hash_remove(&func_hashtab, hi); |
1155 | |
1156 funccal_unref(fp->uf_scoped, fp); | |
1074 | 1157 |
1075 vim_free(fp); | 1158 vim_free(fp); |
1076 } | 1159 } |
1077 | 1160 |
1078 #if defined(EXITFREE) || defined(PROTO) | 1161 #if defined(EXITFREE) || defined(PROTO) |
2214 goto erret; | 2297 goto erret; |
2215 } | 2298 } |
2216 } | 2299 } |
2217 fp->uf_args = newargs; | 2300 fp->uf_args = newargs; |
2218 fp->uf_lines = newlines; | 2301 fp->uf_lines = newlines; |
2302 fp->uf_scoped = NULL; | |
2219 #ifdef FEAT_PROFILE | 2303 #ifdef FEAT_PROFILE |
2220 fp->uf_tml_count = NULL; | 2304 fp->uf_tml_count = NULL; |
2221 fp->uf_tml_total = NULL; | 2305 fp->uf_tml_total = NULL; |
2222 fp->uf_tml_self = NULL; | 2306 fp->uf_tml_self = NULL; |
2223 fp->uf_profiling = FALSE; | 2307 fp->uf_profiling = FALSE; |
2703 static int | 2787 static int |
2704 can_free_funccal(funccall_T *fc, int copyID) | 2788 can_free_funccal(funccall_T *fc, int copyID) |
2705 { | 2789 { |
2706 return (fc->l_varlist.lv_copyID != copyID | 2790 return (fc->l_varlist.lv_copyID != copyID |
2707 && fc->l_vars.dv_copyID != copyID | 2791 && fc->l_vars.dv_copyID != copyID |
2708 && fc->l_avars.dv_copyID != copyID); | 2792 && fc->l_avars.dv_copyID != copyID |
2793 && fc->fc_copyID != copyID); | |
2709 } | 2794 } |
2710 | 2795 |
2711 /* | 2796 /* |
2712 * ":return [expr]" | 2797 * ":return [expr]" |
2713 */ | 2798 */ |
3449 return ¤t_funccal->l_vars; | 3534 return ¤t_funccal->l_vars; |
3450 return NULL; | 3535 return NULL; |
3451 } | 3536 } |
3452 | 3537 |
3453 /* | 3538 /* |
3539 * Search variable in parent scope. | |
3540 */ | |
3541 dictitem_T * | |
3542 find_var_in_scoped_ht(char_u *name, char_u **varname, int no_autoload) | |
3543 { | |
3544 dictitem_T *v = NULL; | |
3545 funccall_T *old_current_funccal = current_funccal; | |
3546 hashtab_T *ht; | |
3547 | |
3548 if (current_funccal == NULL || current_funccal->func->uf_scoped == NULL) | |
3549 return NULL; | |
3550 | |
3551 /* Search in parent scope which is possible to reference from lambda */ | |
3552 current_funccal = current_funccal->func->uf_scoped; | |
3553 while (current_funccal) | |
3554 { | |
3555 ht = find_var_ht(name, varname ? &(*varname) : NULL); | |
3556 if (ht != NULL) | |
3557 { | |
3558 v = find_var_in_ht(ht, *name, | |
3559 varname ? *varname : NULL, no_autoload); | |
3560 if (v != NULL) | |
3561 break; | |
3562 } | |
3563 if (current_funccal == current_funccal->func->uf_scoped) | |
3564 break; | |
3565 current_funccal = current_funccal->func->uf_scoped; | |
3566 } | |
3567 current_funccal = old_current_funccal; | |
3568 | |
3569 return v; | |
3570 } | |
3571 | |
3572 /* | |
3454 * Set "copyID + 1" in previous_funccal and callers. | 3573 * Set "copyID + 1" in previous_funccal and callers. |
3455 */ | 3574 */ |
3456 int | 3575 int |
3457 set_ref_in_previous_funccal(int copyID) | 3576 set_ref_in_previous_funccal(int copyID) |
3458 { | 3577 { |
3459 int abort = FALSE; | 3578 int abort = FALSE; |
3460 funccall_T *fc; | 3579 funccall_T *fc; |
3461 | 3580 |
3462 for (fc = previous_funccal; fc != NULL; fc = fc->caller) | 3581 for (fc = previous_funccal; fc != NULL; fc = fc->caller) |
3463 { | 3582 { |
3583 fc->fc_copyID = copyID + 1; | |
3464 abort = abort || set_ref_in_ht(&fc->l_vars.dv_hashtab, copyID + 1, | 3584 abort = abort || set_ref_in_ht(&fc->l_vars.dv_hashtab, copyID + 1, |
3465 NULL); | 3585 NULL); |
3466 abort = abort || set_ref_in_ht(&fc->l_avars.dv_hashtab, copyID + 1, | 3586 abort = abort || set_ref_in_ht(&fc->l_avars.dv_hashtab, copyID + 1, |
3467 NULL); | 3587 NULL); |
3468 } | 3588 } |
3478 int abort = FALSE; | 3598 int abort = FALSE; |
3479 funccall_T *fc; | 3599 funccall_T *fc; |
3480 | 3600 |
3481 for (fc = current_funccal; fc != NULL; fc = fc->caller) | 3601 for (fc = current_funccal; fc != NULL; fc = fc->caller) |
3482 { | 3602 { |
3603 fc->fc_copyID = copyID; | |
3483 abort = abort || set_ref_in_ht(&fc->l_vars.dv_hashtab, copyID, NULL); | 3604 abort = abort || set_ref_in_ht(&fc->l_vars.dv_hashtab, copyID, NULL); |
3484 abort = abort || set_ref_in_ht(&fc->l_avars.dv_hashtab, copyID, NULL); | 3605 abort = abort || set_ref_in_ht(&fc->l_avars.dv_hashtab, copyID, NULL); |
3485 } | 3606 } |
3486 return abort; | 3607 return abort; |
3487 } | 3608 } |
3499 abort = abort || set_ref_in_item(((typval_T **)funcargs.ga_data)[i], | 3620 abort = abort || set_ref_in_item(((typval_T **)funcargs.ga_data)[i], |
3500 copyID, NULL, NULL); | 3621 copyID, NULL, NULL); |
3501 return abort; | 3622 return abort; |
3502 } | 3623 } |
3503 | 3624 |
3625 /* | |
3626 * Mark all lists and dicts referenced through function "name" with "copyID". | |
3627 * "list_stack" is used to add lists to be marked. Can be NULL. | |
3628 * "ht_stack" is used to add hashtabs to be marked. Can be NULL. | |
3629 * | |
3630 * Returns TRUE if setting references failed somehow. | |
3631 */ | |
3632 int | |
3633 set_ref_in_func(char_u *name, int copyID) | |
3634 { | |
3635 ufunc_T *fp; | |
3636 funccall_T *fc; | |
3637 int error = ERROR_NONE; | |
3638 char_u fname_buf[FLEN_FIXED + 1]; | |
3639 char_u *tofree = NULL; | |
3640 char_u *fname; | |
3641 | |
3642 if (name == NULL) | |
3643 return FALSE; | |
3644 | |
3645 fname = fname_trans_sid(name, fname_buf, &tofree, &error); | |
3646 fp = find_func(fname); | |
3647 if (fp != NULL) | |
3648 { | |
3649 for (fc = fp->uf_scoped; fc != NULL; fc = fc->func->uf_scoped) | |
3650 { | |
3651 if (fc->fc_copyID != copyID) | |
3652 { | |
3653 fc->fc_copyID = copyID; | |
3654 set_ref_in_ht(&fc->l_vars.dv_hashtab, copyID, NULL); | |
3655 set_ref_in_ht(&fc->l_avars.dv_hashtab, copyID, NULL); | |
3656 } | |
3657 } | |
3658 } | |
3659 vim_free(tofree); | |
3660 return FALSE; | |
3661 } | |
3662 | |
3504 #endif /* FEAT_EVAL */ | 3663 #endif /* FEAT_EVAL */ |