Mercurial > vim
comparison src/userfunc.c @ 9688:2ea935bdd1a1 v7.4.2120
commit https://github.com/vim/vim/commit/10ce39a0d52272a3dfff2feb8c631529f29e6740
Author: Bram Moolenaar <Bram@vim.org>
Date: Fri Jul 29 22:37:06 2016 +0200
patch 7.4.2120
Problem: User defined functions can't be a closure.
Solution: Add the "closure" argument. Allow using :unlet on a bound
variable. (Yasuhiro Matsumoto, Ken Takata)
author | Christian Brabandt <cb@256bit.org> |
---|---|
date | Fri, 29 Jul 2016 22:45:06 +0200 |
parents | 8c2553beff0f |
children | 6226de5f8137 |
comparison
equal
deleted
inserted
replaced
9687:a8421d842331 | 9688:2ea935bdd1a1 |
---|---|
57 | 57 |
58 /* function flags */ | 58 /* function flags */ |
59 #define FC_ABORT 1 /* abort function on error */ | 59 #define FC_ABORT 1 /* abort function on error */ |
60 #define FC_RANGE 2 /* function accepts range */ | 60 #define FC_RANGE 2 /* function accepts range */ |
61 #define FC_DICT 4 /* Dict function, uses "self" */ | 61 #define FC_DICT 4 /* Dict function, uses "self" */ |
62 #define FC_CLOSURE 8 /* closure, uses outer scope variables */ | |
62 | 63 |
63 /* From user function to hashitem and back. */ | 64 /* From user function to hashitem and back. */ |
64 #define UF2HIKEY(fp) ((fp)->uf_name) | 65 #define UF2HIKEY(fp) ((fp)->uf_name) |
65 #define HIKEY2UF(p) ((ufunc_T *)(p - offsetof(ufunc_T, uf_name))) | 66 #define HIKEY2UF(p) ((ufunc_T *)(p - offsetof(ufunc_T, uf_name))) |
66 #define HI2UF(hi) HIKEY2UF((hi)->hi_key) | 67 #define HI2UF(hi) HIKEY2UF((hi)->hi_key) |
310 goto errret; | 311 goto errret; |
311 ++*arg; | 312 ++*arg; |
312 | 313 |
313 if (evaluate) | 314 if (evaluate) |
314 { | 315 { |
315 int len; | 316 int len, flags = 0; |
316 char_u *p; | 317 char_u *p; |
317 | 318 |
318 sprintf((char*)name, "<lambda>%d", ++lambda_no); | 319 sprintf((char*)name, "<lambda>%d", ++lambda_no); |
319 | 320 |
320 fp = (ufunc_T *)alloc((unsigned)(sizeof(ufunc_T) + STRLEN(name))); | 321 fp = (ufunc_T *)alloc((unsigned)(sizeof(ufunc_T) + STRLEN(name))); |
339 hash_add(&func_hashtab, UF2HIKEY(fp)); | 340 hash_add(&func_hashtab, UF2HIKEY(fp)); |
340 fp->uf_args = newargs; | 341 fp->uf_args = newargs; |
341 fp->uf_lines = newlines; | 342 fp->uf_lines = newlines; |
342 if (current_funccal != NULL && eval_lavars) | 343 if (current_funccal != NULL && eval_lavars) |
343 { | 344 { |
345 flags |= FC_CLOSURE; | |
344 fp->uf_scoped = current_funccal; | 346 fp->uf_scoped = current_funccal; |
345 current_funccal->fc_refcount++; | 347 current_funccal->fc_refcount++; |
346 if (ga_grow(¤t_funccal->fc_funcs, 1) == FAIL) | 348 if (ga_grow(¤t_funccal->fc_funcs, 1) == FAIL) |
347 goto errret; | 349 goto errret; |
348 ((ufunc_T **)current_funccal->fc_funcs.ga_data) | 350 ((ufunc_T **)current_funccal->fc_funcs.ga_data) |
359 fp->uf_profiling = FALSE; | 361 fp->uf_profiling = FALSE; |
360 if (prof_def_func()) | 362 if (prof_def_func()) |
361 func_do_profile(fp); | 363 func_do_profile(fp); |
362 #endif | 364 #endif |
363 fp->uf_varargs = TRUE; | 365 fp->uf_varargs = TRUE; |
364 fp->uf_flags = 0; | 366 fp->uf_flags = flags; |
365 fp->uf_calls = 0; | 367 fp->uf_calls = 0; |
366 fp->uf_script_ID = current_SID; | 368 fp->uf_script_ID = current_SID; |
367 | 369 |
368 rettv->vval.v_string = vim_strsave(name); | 370 rettv->vval.v_string = vim_strsave(name); |
369 rettv->v_type = VAR_FUNC; | 371 rettv->v_type = VAR_FUNC; |
1485 MSG_PUTS(" abort"); | 1487 MSG_PUTS(" abort"); |
1486 if (fp->uf_flags & FC_RANGE) | 1488 if (fp->uf_flags & FC_RANGE) |
1487 MSG_PUTS(" range"); | 1489 MSG_PUTS(" range"); |
1488 if (fp->uf_flags & FC_DICT) | 1490 if (fp->uf_flags & FC_DICT) |
1489 MSG_PUTS(" dict"); | 1491 MSG_PUTS(" dict"); |
1492 if (fp->uf_flags & FC_CLOSURE) | |
1493 MSG_PUTS(" closure"); | |
1490 msg_clr_eos(); | 1494 msg_clr_eos(); |
1491 if (p_verbose > 0) | 1495 if (p_verbose > 0) |
1492 last_set_msg(fp->uf_script_ID); | 1496 last_set_msg(fp->uf_script_ID); |
1493 } | 1497 } |
1494 | 1498 |
1946 } | 1950 } |
1947 | 1951 |
1948 if (get_function_args(&p, ')', &newargs, &varargs, eap->skip) == FAIL) | 1952 if (get_function_args(&p, ')', &newargs, &varargs, eap->skip) == FAIL) |
1949 goto errret_2; | 1953 goto errret_2; |
1950 | 1954 |
1951 /* find extra arguments "range", "dict" and "abort" */ | 1955 /* find extra arguments "range", "dict", "abort" and "closure" */ |
1952 for (;;) | 1956 for (;;) |
1953 { | 1957 { |
1954 p = skipwhite(p); | 1958 p = skipwhite(p); |
1955 if (STRNCMP(p, "range", 5) == 0) | 1959 if (STRNCMP(p, "range", 5) == 0) |
1956 { | 1960 { |
1964 } | 1968 } |
1965 else if (STRNCMP(p, "abort", 5) == 0) | 1969 else if (STRNCMP(p, "abort", 5) == 0) |
1966 { | 1970 { |
1967 flags |= FC_ABORT; | 1971 flags |= FC_ABORT; |
1968 p += 5; | 1972 p += 5; |
1973 } | |
1974 else if (STRNCMP(p, "closure", 7) == 0) | |
1975 { | |
1976 flags |= FC_CLOSURE; | |
1977 p += 7; | |
1969 } | 1978 } |
1970 else | 1979 else |
1971 break; | 1980 break; |
1972 } | 1981 } |
1973 | 1982 |
2297 goto erret; | 2306 goto erret; |
2298 } | 2307 } |
2299 } | 2308 } |
2300 fp->uf_args = newargs; | 2309 fp->uf_args = newargs; |
2301 fp->uf_lines = newlines; | 2310 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(¤t_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 | |
2303 #ifdef FEAT_PROFILE | 2330 #ifdef FEAT_PROFILE |
2304 fp->uf_tml_count = NULL; | 2331 fp->uf_tml_count = NULL; |
2305 fp->uf_tml_total = NULL; | 2332 fp->uf_tml_total = NULL; |
2306 fp->uf_tml_self = NULL; | 2333 fp->uf_tml_self = NULL; |
2307 fp->uf_profiling = FALSE; | 2334 fp->uf_profiling = FALSE; |
3534 return ¤t_funccal->l_vars; | 3561 return ¤t_funccal->l_vars; |
3535 return NULL; | 3562 return NULL; |
3536 } | 3563 } |
3537 | 3564 |
3538 /* | 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 | |
3601 /* | |
3539 * Search variable in parent scope. | 3602 * Search variable in parent scope. |
3540 */ | 3603 */ |
3541 dictitem_T * | 3604 dictitem_T * |
3542 find_var_in_scoped_ht(char_u *name, char_u **varname, int no_autoload) | 3605 find_var_in_scoped_ht(char_u *name, char_u **varname, int no_autoload) |
3543 { | 3606 { |