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(&current_funccal->fc_funcs, 1) == FAIL) 348 if (ga_grow(&current_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(&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
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 &current_funccal->l_vars; 3561 return &current_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 {