1edf3f97aSBram Moolenaar /* vi:set ts=8 sts=4 sw=4 noet:
2a9b579f3SBram Moolenaar *
3a9b579f3SBram Moolenaar * VIM - Vi IMproved by Bram Moolenaar
4a9b579f3SBram Moolenaar *
5a9b579f3SBram Moolenaar * Do ":help uganda" in Vim to read copying and usage conditions.
6a9b579f3SBram Moolenaar * Do ":help credits" in Vim to see a list of people who contributed.
7a9b579f3SBram Moolenaar * See README.txt for an overview of the Vim source code.
8a9b579f3SBram Moolenaar */
9a9b579f3SBram Moolenaar
10a9b579f3SBram Moolenaar /*
1114c01f83SBram Moolenaar * userfunc.c: User defined function support
12a9b579f3SBram Moolenaar */
13a9b579f3SBram Moolenaar
14a9b579f3SBram Moolenaar #include "vim.h"
15a9b579f3SBram Moolenaar
16a9b579f3SBram Moolenaar #if defined(FEAT_EVAL) || defined(PROTO)
17a9b579f3SBram Moolenaar /*
18a9b579f3SBram Moolenaar * All user-defined functions are found in this hashtable.
19a9b579f3SBram Moolenaar */
20a9b579f3SBram Moolenaar static hashtab_T func_hashtab;
21a9b579f3SBram Moolenaar
22e38eab22SBram Moolenaar // Used by get_func_tv()
23a9b579f3SBram Moolenaar static garray_T funcargs = GA_EMPTY;
24a9b579f3SBram Moolenaar
25209b8e3eSBram Moolenaar // pointer to funccal for currently active function
26209b8e3eSBram Moolenaar static funccall_T *current_funccal = NULL;
27a9b579f3SBram Moolenaar
28209b8e3eSBram Moolenaar // Pointer to list of previously used funccal, still around because some
29209b8e3eSBram Moolenaar // item in it is still being used.
30209b8e3eSBram Moolenaar static funccall_T *previous_funccal = NULL;
31a9b579f3SBram Moolenaar
32a9b579f3SBram Moolenaar static char *e_funcexts = N_("E122: Function %s already exists, add ! to replace it");
33a9b579f3SBram Moolenaar static char *e_funcdict = N_("E717: Dictionary entry already exists");
34a9b579f3SBram Moolenaar static char *e_funcref = N_("E718: Funcref required");
35a9b579f3SBram Moolenaar static char *e_nofunc = N_("E130: Unknown function: %s");
36a9b579f3SBram Moolenaar
37bc7ce675SBram Moolenaar static void funccal_unref(funccall_T *fc, ufunc_T *fp, int force);
3879efa2e3SBram Moolenaar static void func_clear(ufunc_T *fp, int force);
3979efa2e3SBram Moolenaar static int func_free(ufunc_T *fp, int force);
40a9b579f3SBram Moolenaar
41a9b579f3SBram Moolenaar void
func_init()42a9b579f3SBram Moolenaar func_init()
43a9b579f3SBram Moolenaar {
44a9b579f3SBram Moolenaar hash_init(&func_hashtab);
45a9b579f3SBram Moolenaar }
46a9b579f3SBram Moolenaar
474f0383bcSBram Moolenaar /*
48660a10adSBram Moolenaar * Return the function hash table
49660a10adSBram Moolenaar */
50660a10adSBram Moolenaar hashtab_T *
func_tbl_get(void)51660a10adSBram Moolenaar func_tbl_get(void)
52660a10adSBram Moolenaar {
53660a10adSBram Moolenaar return &func_hashtab;
54660a10adSBram Moolenaar }
55660a10adSBram Moolenaar
56660a10adSBram Moolenaar /*
576e949784SBram Moolenaar * Get one function argument.
5851e7e78dSBram Moolenaar * If "argtypes" is not NULL also get the type: "arg: type" (:def function).
59b4d16cb1SBram Moolenaar * If "types_optional" is TRUE a missing type is OK, use "any".
60057e84afSBram Moolenaar * If "evalarg" is not NULL use it to check for an already declared name.
618a7d6542SBram Moolenaar * Return a pointer to after the type.
628a7d6542SBram Moolenaar * When something is wrong return "arg".
638a7d6542SBram Moolenaar */
648a7d6542SBram Moolenaar static char_u *
one_function_arg(char_u * arg,garray_T * newargs,garray_T * argtypes,int types_optional,evalarg_T * evalarg,int is_vararg,int skip)65b4d16cb1SBram Moolenaar one_function_arg(
66b4d16cb1SBram Moolenaar char_u *arg,
67b4d16cb1SBram Moolenaar garray_T *newargs,
68b4d16cb1SBram Moolenaar garray_T *argtypes,
69b4d16cb1SBram Moolenaar int types_optional,
70057e84afSBram Moolenaar evalarg_T *evalarg,
712a38908bSBram Moolenaar int is_vararg,
72b4d16cb1SBram Moolenaar int skip)
738a7d6542SBram Moolenaar {
748a7d6542SBram Moolenaar char_u *p = arg;
756e949784SBram Moolenaar char_u *arg_copy = NULL;
7651e7e78dSBram Moolenaar int is_underscore = FALSE;
778a7d6542SBram Moolenaar
788a7d6542SBram Moolenaar while (ASCII_ISALNUM(*p) || *p == '_')
798a7d6542SBram Moolenaar ++p;
808a7d6542SBram Moolenaar if (arg == p || isdigit(*arg)
81b816dae1SBram Moolenaar || (argtypes == NULL
82b816dae1SBram Moolenaar && ((p - arg == 9 && STRNCMP(arg, "firstline", 9) == 0)
83b816dae1SBram Moolenaar || (p - arg == 8 && STRNCMP(arg, "lastline", 8) == 0))))
848a7d6542SBram Moolenaar {
858a7d6542SBram Moolenaar if (!skip)
868a7d6542SBram Moolenaar semsg(_("E125: Illegal argument: %s"), arg);
878a7d6542SBram Moolenaar return arg;
888a7d6542SBram Moolenaar }
89b4893b84SBram Moolenaar
90057e84afSBram Moolenaar // Vim9 script: cannot use script var name for argument. In function: also
91057e84afSBram Moolenaar // check local vars and arguments.
92057e84afSBram Moolenaar if (!skip && argtypes != NULL && check_defined(arg, p - arg,
93057e84afSBram Moolenaar evalarg == NULL ? NULL : evalarg->eval_cctx, TRUE) == FAIL)
94b4893b84SBram Moolenaar return arg;
95b4893b84SBram Moolenaar
968a7d6542SBram Moolenaar if (newargs != NULL && ga_grow(newargs, 1) == FAIL)
978a7d6542SBram Moolenaar return arg;
988a7d6542SBram Moolenaar if (newargs != NULL)
998a7d6542SBram Moolenaar {
1008a7d6542SBram Moolenaar int c;
1018a7d6542SBram Moolenaar int i;
1028a7d6542SBram Moolenaar
1038a7d6542SBram Moolenaar c = *p;
1048a7d6542SBram Moolenaar *p = NUL;
1058a7d6542SBram Moolenaar arg_copy = vim_strsave(arg);
1068a7d6542SBram Moolenaar if (arg_copy == NULL)
1078a7d6542SBram Moolenaar {
1088a7d6542SBram Moolenaar *p = c;
1098a7d6542SBram Moolenaar return arg;
1108a7d6542SBram Moolenaar }
11151e7e78dSBram Moolenaar is_underscore = arg_copy[0] == '_' && arg_copy[1] == NUL;
11287795939SBram Moolenaar if (argtypes == NULL || !is_underscore)
1138a7d6542SBram Moolenaar // Check for duplicate argument name.
1148a7d6542SBram Moolenaar for (i = 0; i < newargs->ga_len; ++i)
1158a7d6542SBram Moolenaar if (STRCMP(((char_u **)(newargs->ga_data))[i], arg_copy) == 0)
1168a7d6542SBram Moolenaar {
1178a7d6542SBram Moolenaar semsg(_("E853: Duplicate argument name: %s"), arg_copy);
1188a7d6542SBram Moolenaar vim_free(arg_copy);
1198a7d6542SBram Moolenaar return arg;
1208a7d6542SBram Moolenaar }
1218a7d6542SBram Moolenaar ((char_u **)(newargs->ga_data))[newargs->ga_len] = arg_copy;
1228a7d6542SBram Moolenaar newargs->ga_len++;
1238a7d6542SBram Moolenaar
1248a7d6542SBram Moolenaar *p = c;
1258a7d6542SBram Moolenaar }
1268a7d6542SBram Moolenaar
1278a7d6542SBram Moolenaar // get any type from "arg: type"
128b4d16cb1SBram Moolenaar if (argtypes != NULL && (skip || ga_grow(argtypes, 1) == OK))
1298a7d6542SBram Moolenaar {
1308a7d6542SBram Moolenaar char_u *type = NULL;
1318a7d6542SBram Moolenaar
1326e949784SBram Moolenaar if (VIM_ISWHITE(*p) && *skipwhite(p) == ':')
1336e949784SBram Moolenaar {
134451c2e35SBram Moolenaar semsg(_(e_no_white_space_allowed_before_colon_str),
1356e949784SBram Moolenaar arg_copy == NULL ? arg : arg_copy);
1366e949784SBram Moolenaar p = skipwhite(p);
1376e949784SBram Moolenaar }
1388a7d6542SBram Moolenaar if (*p == ':')
1398a7d6542SBram Moolenaar {
140f93c7feaSBram Moolenaar ++p;
141b4d16cb1SBram Moolenaar if (!skip && !VIM_ISWHITE(*p))
142f93c7feaSBram Moolenaar {
143c3fc75dbSBram Moolenaar semsg(_(e_white_space_required_after_str_str), ":", p - 1);
144f93c7feaSBram Moolenaar return arg;
145f93c7feaSBram Moolenaar }
146f93c7feaSBram Moolenaar type = skipwhite(p);
1474fc224caSBram Moolenaar p = skip_type(type, TRUE);
148b4d16cb1SBram Moolenaar if (!skip)
1498a7d6542SBram Moolenaar type = vim_strnsave(type, p - type);
1508a7d6542SBram Moolenaar }
15151e7e78dSBram Moolenaar else if (*skipwhite(p) != '=' && !types_optional && !is_underscore)
1526e949784SBram Moolenaar {
153451c2e35SBram Moolenaar semsg(_(e_missing_argument_type_for_str),
1546e949784SBram Moolenaar arg_copy == NULL ? arg : arg_copy);
1556e949784SBram Moolenaar return arg;
1566e949784SBram Moolenaar }
157b4d16cb1SBram Moolenaar if (!skip)
158b4d16cb1SBram Moolenaar {
159b4d16cb1SBram Moolenaar if (type == NULL && types_optional)
160b4d16cb1SBram Moolenaar // lambda arguments default to "any" type
1612a38908bSBram Moolenaar type = vim_strsave((char_u *)
1622a38908bSBram Moolenaar (is_vararg ? "list<any>" : "any"));
1638a7d6542SBram Moolenaar ((char_u **)argtypes->ga_data)[argtypes->ga_len++] = type;
1648a7d6542SBram Moolenaar }
165b4d16cb1SBram Moolenaar }
1668a7d6542SBram Moolenaar
1678a7d6542SBram Moolenaar return p;
1688a7d6542SBram Moolenaar }
1698a7d6542SBram Moolenaar
1708a7d6542SBram Moolenaar /*
1714f0383bcSBram Moolenaar * Get function arguments.
172cef1270dSBram Moolenaar * "argp" should point to just after the "(", possibly to white space.
17365c44152SBram Moolenaar * "argp" is advanced just after "endchar".
1744f0383bcSBram Moolenaar */
175cef1270dSBram Moolenaar static int
get_function_args(char_u ** argp,char_u endchar,garray_T * newargs,garray_T * argtypes,int types_optional,evalarg_T * evalarg,int * varargs,garray_T * default_args,int skip,exarg_T * eap,char_u ** line_to_free)176a9b579f3SBram Moolenaar get_function_args(
177a9b579f3SBram Moolenaar char_u **argp,
178a9b579f3SBram Moolenaar char_u endchar,
179a9b579f3SBram Moolenaar garray_T *newargs,
1808a7d6542SBram Moolenaar garray_T *argtypes, // NULL unless using :def
181b4d16cb1SBram Moolenaar int types_optional, // types optional if "argtypes" is not NULL
182057e84afSBram Moolenaar evalarg_T *evalarg, // context or NULL
183a9b579f3SBram Moolenaar int *varargs,
18442ae78cfSBram Moolenaar garray_T *default_args,
1855e774c75SBram Moolenaar int skip,
1865e774c75SBram Moolenaar exarg_T *eap,
1875e774c75SBram Moolenaar char_u **line_to_free)
188a9b579f3SBram Moolenaar {
189a9b579f3SBram Moolenaar int mustend = FALSE;
190cef1270dSBram Moolenaar char_u *arg;
191cef1270dSBram Moolenaar char_u *p;
192a9b579f3SBram Moolenaar int c;
19342ae78cfSBram Moolenaar int any_default = FALSE;
19442ae78cfSBram Moolenaar char_u *expr;
195cef1270dSBram Moolenaar char_u *whitep = *argp;
196a9b579f3SBram Moolenaar
197a9b579f3SBram Moolenaar if (newargs != NULL)
198a9b579f3SBram Moolenaar ga_init2(newargs, (int)sizeof(char_u *), 3);
1998a7d6542SBram Moolenaar if (argtypes != NULL)
2008a7d6542SBram Moolenaar ga_init2(argtypes, (int)sizeof(char_u *), 3);
201e3ffaa6bSBram Moolenaar if (!skip && default_args != NULL)
20242ae78cfSBram Moolenaar ga_init2(default_args, (int)sizeof(char_u *), 3);
203a9b579f3SBram Moolenaar
204a9b579f3SBram Moolenaar if (varargs != NULL)
205a9b579f3SBram Moolenaar *varargs = FALSE;
206a9b579f3SBram Moolenaar
207a9b579f3SBram Moolenaar /*
208a9b579f3SBram Moolenaar * Isolate the arguments: "arg1, arg2, ...)"
209a9b579f3SBram Moolenaar */
210cef1270dSBram Moolenaar arg = skipwhite(*argp);
211cef1270dSBram Moolenaar p = arg;
212a9b579f3SBram Moolenaar while (*p != endchar)
213a9b579f3SBram Moolenaar {
2142c330432SBram Moolenaar while (eap != NULL && eap->getline != NULL
2152c330432SBram Moolenaar && (*p == NUL || (VIM_ISWHITE(*whitep) && *p == '#')))
2165e774c75SBram Moolenaar {
2175e774c75SBram Moolenaar char_u *theline;
2185e774c75SBram Moolenaar
2195e774c75SBram Moolenaar // End of the line, get the next one.
2205e774c75SBram Moolenaar theline = eap->getline(':', eap->cookie, 0, TRUE);
2215e774c75SBram Moolenaar if (theline == NULL)
2225e774c75SBram Moolenaar break;
2235e774c75SBram Moolenaar vim_free(*line_to_free);
2245e774c75SBram Moolenaar *line_to_free = theline;
2252c330432SBram Moolenaar whitep = (char_u *)" ";
2265e774c75SBram Moolenaar p = skipwhite(theline);
2275e774c75SBram Moolenaar }
2285e774c75SBram Moolenaar
2295e774c75SBram Moolenaar if (mustend && *p != endchar)
2305e774c75SBram Moolenaar {
2315e774c75SBram Moolenaar if (!skip)
2325e774c75SBram Moolenaar semsg(_(e_invarg2), *argp);
233b4d16cb1SBram Moolenaar goto err_ret;
2345e774c75SBram Moolenaar }
2355e774c75SBram Moolenaar if (*p == endchar)
2365e774c75SBram Moolenaar break;
2375e774c75SBram Moolenaar
238a9b579f3SBram Moolenaar if (p[0] == '.' && p[1] == '.' && p[2] == '.')
239a9b579f3SBram Moolenaar {
240a9b579f3SBram Moolenaar if (varargs != NULL)
241a9b579f3SBram Moolenaar *varargs = TRUE;
242a9b579f3SBram Moolenaar p += 3;
243a9b579f3SBram Moolenaar mustend = TRUE;
2448a7d6542SBram Moolenaar
2458a7d6542SBram Moolenaar if (argtypes != NULL)
2468a7d6542SBram Moolenaar {
2478a7d6542SBram Moolenaar // ...name: list<type>
24828022727SBram Moolenaar if (!eval_isnamec1(*p))
2498a7d6542SBram Moolenaar {
250b4d16cb1SBram Moolenaar if (!skip)
251451c2e35SBram Moolenaar emsg(_(e_missing_name_after_dots));
252b4d16cb1SBram Moolenaar goto err_ret;
2538a7d6542SBram Moolenaar }
2548a7d6542SBram Moolenaar
2558a7d6542SBram Moolenaar arg = p;
256b4d16cb1SBram Moolenaar p = one_function_arg(p, newargs, argtypes, types_optional,
2572a38908bSBram Moolenaar evalarg, TRUE, skip);
2588a7d6542SBram Moolenaar if (p == arg)
2598a7d6542SBram Moolenaar break;
2604f53b79bSBram Moolenaar if (*skipwhite(p) == '=')
2614f53b79bSBram Moolenaar {
2624f53b79bSBram Moolenaar emsg(_(e_cannot_use_default_for_variable_arguments));
2634f53b79bSBram Moolenaar break;
2644f53b79bSBram Moolenaar }
2658a7d6542SBram Moolenaar }
266a9b579f3SBram Moolenaar }
267a9b579f3SBram Moolenaar else
268a9b579f3SBram Moolenaar {
269015cf103SBram Moolenaar char_u *np;
270015cf103SBram Moolenaar
271a9b579f3SBram Moolenaar arg = p;
272057e84afSBram Moolenaar p = one_function_arg(p, newargs, argtypes, types_optional,
2732a38908bSBram Moolenaar evalarg, FALSE, skip);
2748a7d6542SBram Moolenaar if (p == arg)
275a9b579f3SBram Moolenaar break;
276a9b579f3SBram Moolenaar
277015cf103SBram Moolenaar // Recognize " = expr" but not " == expr". A lambda can have
27898f9a5f4SBram Moolenaar // "(a = expr" but "(a == expr" and "(a =~ expr" are not a lambda.
279015cf103SBram Moolenaar np = skipwhite(p);
28098f9a5f4SBram Moolenaar if (*np == '=' && np[1] != '=' && np[1] != '~'
28198f9a5f4SBram Moolenaar && default_args != NULL)
28242ae78cfSBram Moolenaar {
28342ae78cfSBram Moolenaar typval_T rettv;
28442ae78cfSBram Moolenaar
285170fcfcfSBram Moolenaar // find the end of the expression (doesn't evaluate it)
28642ae78cfSBram Moolenaar any_default = TRUE;
28742ae78cfSBram Moolenaar p = skipwhite(p) + 1;
2882c330432SBram Moolenaar whitep = p;
28942ae78cfSBram Moolenaar p = skipwhite(p);
29042ae78cfSBram Moolenaar expr = p;
2915409f5d8SBram Moolenaar if (eval1(&p, &rettv, NULL) != FAIL)
29242ae78cfSBram Moolenaar {
293e3ffaa6bSBram Moolenaar if (!skip)
294e3ffaa6bSBram Moolenaar {
29542ae78cfSBram Moolenaar if (ga_grow(default_args, 1) == FAIL)
29642ae78cfSBram Moolenaar goto err_ret;
29742ae78cfSBram Moolenaar
29842ae78cfSBram Moolenaar // trim trailing whitespace
29942ae78cfSBram Moolenaar while (p > expr && VIM_ISWHITE(p[-1]))
30042ae78cfSBram Moolenaar p--;
30142ae78cfSBram Moolenaar c = *p;
30242ae78cfSBram Moolenaar *p = NUL;
30342ae78cfSBram Moolenaar expr = vim_strsave(expr);
30442ae78cfSBram Moolenaar if (expr == NULL)
30542ae78cfSBram Moolenaar {
30642ae78cfSBram Moolenaar *p = c;
30742ae78cfSBram Moolenaar goto err_ret;
30842ae78cfSBram Moolenaar }
30942ae78cfSBram Moolenaar ((char_u **)(default_args->ga_data))
31042ae78cfSBram Moolenaar [default_args->ga_len] = expr;
31142ae78cfSBram Moolenaar default_args->ga_len++;
31242ae78cfSBram Moolenaar *p = c;
31342ae78cfSBram Moolenaar }
314e3ffaa6bSBram Moolenaar }
31542ae78cfSBram Moolenaar else
31642ae78cfSBram Moolenaar mustend = TRUE;
31742ae78cfSBram Moolenaar }
31842ae78cfSBram Moolenaar else if (any_default)
31942ae78cfSBram Moolenaar {
32042ae78cfSBram Moolenaar emsg(_("E989: Non-default argument follows default argument"));
321914e7eaaSBram Moolenaar goto err_ret;
32242ae78cfSBram Moolenaar }
32386cdb8a4SBram Moolenaar
32486cdb8a4SBram Moolenaar if (VIM_ISWHITE(*p) && *skipwhite(p) == ',')
32586cdb8a4SBram Moolenaar {
32686cdb8a4SBram Moolenaar // Be tolerant when skipping
32786cdb8a4SBram Moolenaar if (!skip)
32886cdb8a4SBram Moolenaar {
32986cdb8a4SBram Moolenaar semsg(_(e_no_white_space_allowed_before_str_str), ",", p);
33086cdb8a4SBram Moolenaar goto err_ret;
33186cdb8a4SBram Moolenaar }
33286cdb8a4SBram Moolenaar p = skipwhite(p);
33386cdb8a4SBram Moolenaar }
334a9b579f3SBram Moolenaar if (*p == ',')
335914e7eaaSBram Moolenaar {
336a9b579f3SBram Moolenaar ++p;
337914e7eaaSBram Moolenaar // Don't give this error when skipping, it makes the "->" not
338914e7eaaSBram Moolenaar // found in "{k,v -> x}" and give a confusing error.
339608d78fbSBram Moolenaar // Allow missing space after comma in legacy functions.
340608d78fbSBram Moolenaar if (!skip && argtypes != NULL
341914e7eaaSBram Moolenaar && !IS_WHITE_OR_NUL(*p) && *p != endchar)
342914e7eaaSBram Moolenaar {
343c3fc75dbSBram Moolenaar semsg(_(e_white_space_required_after_str_str), ",", p - 1);
344914e7eaaSBram Moolenaar goto err_ret;
345914e7eaaSBram Moolenaar }
346914e7eaaSBram Moolenaar }
347a9b579f3SBram Moolenaar else
348a9b579f3SBram Moolenaar mustend = TRUE;
349a9b579f3SBram Moolenaar }
3502c330432SBram Moolenaar whitep = p;
351a9b579f3SBram Moolenaar p = skipwhite(p);
352a9b579f3SBram Moolenaar }
3535e774c75SBram Moolenaar
3544f0383bcSBram Moolenaar if (*p != endchar)
3554f0383bcSBram Moolenaar goto err_ret;
356e38eab22SBram Moolenaar ++p; // skip "endchar"
357a9b579f3SBram Moolenaar
358a9b579f3SBram Moolenaar *argp = p;
359a9b579f3SBram Moolenaar return OK;
360a9b579f3SBram Moolenaar
361a9b579f3SBram Moolenaar err_ret:
362a9b579f3SBram Moolenaar if (newargs != NULL)
363a9b579f3SBram Moolenaar ga_clear_strings(newargs);
364e3ffaa6bSBram Moolenaar if (!skip && default_args != NULL)
36542ae78cfSBram Moolenaar ga_clear_strings(default_args);
366a9b579f3SBram Moolenaar return FAIL;
367a9b579f3SBram Moolenaar }
368a9b579f3SBram Moolenaar
369a9b579f3SBram Moolenaar /*
370b4d16cb1SBram Moolenaar * Parse the argument types, filling "fp->uf_arg_types".
371b4d16cb1SBram Moolenaar * Return OK or FAIL.
372b4d16cb1SBram Moolenaar */
373b4d16cb1SBram Moolenaar static int
parse_argument_types(ufunc_T * fp,garray_T * argtypes,int varargs)374b4d16cb1SBram Moolenaar parse_argument_types(ufunc_T *fp, garray_T *argtypes, int varargs)
375b4d16cb1SBram Moolenaar {
3762a38908bSBram Moolenaar int len = 0;
3772a38908bSBram Moolenaar
378b4d16cb1SBram Moolenaar ga_init2(&fp->uf_type_list, sizeof(type_T *), 10);
379b4d16cb1SBram Moolenaar if (argtypes->ga_len > 0)
380b4d16cb1SBram Moolenaar {
381b4d16cb1SBram Moolenaar // When "varargs" is set the last name/type goes into uf_va_name
382b4d16cb1SBram Moolenaar // and uf_va_type.
3832a38908bSBram Moolenaar len = argtypes->ga_len - (varargs ? 1 : 0);
384b4d16cb1SBram Moolenaar
385b4d16cb1SBram Moolenaar if (len > 0)
386b4d16cb1SBram Moolenaar fp->uf_arg_types = ALLOC_CLEAR_MULT(type_T *, len);
387b4d16cb1SBram Moolenaar if (fp->uf_arg_types != NULL)
388b4d16cb1SBram Moolenaar {
389b4d16cb1SBram Moolenaar int i;
390b4d16cb1SBram Moolenaar type_T *type;
391b4d16cb1SBram Moolenaar
392b4d16cb1SBram Moolenaar for (i = 0; i < len; ++ i)
393b4d16cb1SBram Moolenaar {
394b4d16cb1SBram Moolenaar char_u *p = ((char_u **)argtypes->ga_data)[i];
395b4d16cb1SBram Moolenaar
396b4d16cb1SBram Moolenaar if (p == NULL)
397b4d16cb1SBram Moolenaar // will get the type from the default value
398b4d16cb1SBram Moolenaar type = &t_unknown;
399b4d16cb1SBram Moolenaar else
4009e68c325SBram Moolenaar type = parse_type(&p, &fp->uf_type_list, TRUE);
401b4d16cb1SBram Moolenaar if (type == NULL)
402b4d16cb1SBram Moolenaar return FAIL;
403b4d16cb1SBram Moolenaar fp->uf_arg_types[i] = type;
404b4d16cb1SBram Moolenaar }
405b4d16cb1SBram Moolenaar }
4062a38908bSBram Moolenaar }
4072a38908bSBram Moolenaar
408b4d16cb1SBram Moolenaar if (varargs)
409b4d16cb1SBram Moolenaar {
410b4d16cb1SBram Moolenaar char_u *p;
411b4d16cb1SBram Moolenaar
412b4d16cb1SBram Moolenaar // Move the last argument "...name: type" to uf_va_name and
413b4d16cb1SBram Moolenaar // uf_va_type.
414b4d16cb1SBram Moolenaar fp->uf_va_name = ((char_u **)fp->uf_args.ga_data)
415b4d16cb1SBram Moolenaar [fp->uf_args.ga_len - 1];
416b4d16cb1SBram Moolenaar --fp->uf_args.ga_len;
417b4d16cb1SBram Moolenaar p = ((char_u **)argtypes->ga_data)[len];
418b4d16cb1SBram Moolenaar if (p == NULL)
4192a38908bSBram Moolenaar // TODO: get type from default value
4202a38908bSBram Moolenaar fp->uf_va_type = &t_list_any;
421b4d16cb1SBram Moolenaar else
4222a38908bSBram Moolenaar {
4239e68c325SBram Moolenaar fp->uf_va_type = parse_type(&p, &fp->uf_type_list, TRUE);
4242a38908bSBram Moolenaar if (fp->uf_va_type != NULL && fp->uf_va_type->tt_type != VAR_LIST)
4252a38908bSBram Moolenaar {
4262a38908bSBram Moolenaar semsg(_(e_variable_arguments_type_must_be_list_str),
4272a38908bSBram Moolenaar ((char_u **)argtypes->ga_data)[len]);
428b4d16cb1SBram Moolenaar return FAIL;
429b4d16cb1SBram Moolenaar }
430b4d16cb1SBram Moolenaar }
4312a38908bSBram Moolenaar if (fp->uf_va_type == NULL)
4322a38908bSBram Moolenaar return FAIL;
4332a38908bSBram Moolenaar }
4342a38908bSBram Moolenaar
435b4d16cb1SBram Moolenaar return OK;
436b4d16cb1SBram Moolenaar }
437b4d16cb1SBram Moolenaar
4387a6eaa06SBram Moolenaar static int
parse_return_type(ufunc_T * fp,char_u * ret_type)4397a6eaa06SBram Moolenaar parse_return_type(ufunc_T *fp, char_u *ret_type)
4407a6eaa06SBram Moolenaar {
4417a6eaa06SBram Moolenaar if (ret_type == NULL)
4427a6eaa06SBram Moolenaar fp->uf_ret_type = &t_void;
4437a6eaa06SBram Moolenaar else
4447a6eaa06SBram Moolenaar {
4457a6eaa06SBram Moolenaar char_u *p = ret_type;
4467a6eaa06SBram Moolenaar
4477a6eaa06SBram Moolenaar fp->uf_ret_type = parse_type(&p, &fp->uf_type_list, TRUE);
4487a6eaa06SBram Moolenaar if (fp->uf_ret_type == NULL)
4497a6eaa06SBram Moolenaar {
4507a6eaa06SBram Moolenaar fp->uf_ret_type = &t_void;
4517a6eaa06SBram Moolenaar return FAIL;
4527a6eaa06SBram Moolenaar }
4537a6eaa06SBram Moolenaar }
4547a6eaa06SBram Moolenaar return OK;
4557a6eaa06SBram Moolenaar }
4567a6eaa06SBram Moolenaar
457b4d16cb1SBram Moolenaar /*
45858016448SBram Moolenaar * Register function "fp" as using "current_funccal" as its scope.
45958016448SBram Moolenaar */
46058016448SBram Moolenaar static int
register_closure(ufunc_T * fp)46158016448SBram Moolenaar register_closure(ufunc_T *fp)
46258016448SBram Moolenaar {
4638dd3a43dSBram Moolenaar if (fp->uf_scoped == current_funccal)
464e38eab22SBram Moolenaar // no change
4658dd3a43dSBram Moolenaar return OK;
466bc7ce675SBram Moolenaar funccal_unref(fp->uf_scoped, fp, FALSE);
46758016448SBram Moolenaar fp->uf_scoped = current_funccal;
46858016448SBram Moolenaar current_funccal->fc_refcount++;
4698dd3a43dSBram Moolenaar
47058016448SBram Moolenaar if (ga_grow(¤t_funccal->fc_funcs, 1) == FAIL)
47158016448SBram Moolenaar return FAIL;
47258016448SBram Moolenaar ((ufunc_T **)current_funccal->fc_funcs.ga_data)
47358016448SBram Moolenaar [current_funccal->fc_funcs.ga_len++] = fp;
47458016448SBram Moolenaar return OK;
47558016448SBram Moolenaar }
47658016448SBram Moolenaar
4771a47ae32SBram Moolenaar static void
set_ufunc_name(ufunc_T * fp,char_u * name)4781a47ae32SBram Moolenaar set_ufunc_name(ufunc_T *fp, char_u *name)
4791a47ae32SBram Moolenaar {
4807b6903f0SBram Moolenaar // Add a type cast to avoid a warning for an overflow, the uf_name[] array
4817b6903f0SBram Moolenaar // actually extends beyond the struct.
4827b6903f0SBram Moolenaar STRCPY((void *)fp->uf_name, name);
4831a47ae32SBram Moolenaar
4841a47ae32SBram Moolenaar if (name[0] == K_SPECIAL)
4851a47ae32SBram Moolenaar {
4861a47ae32SBram Moolenaar fp->uf_name_exp = alloc(STRLEN(name) + 3);
4871a47ae32SBram Moolenaar if (fp->uf_name_exp != NULL)
4881a47ae32SBram Moolenaar {
4891a47ae32SBram Moolenaar STRCPY(fp->uf_name_exp, "<SNR>");
4901a47ae32SBram Moolenaar STRCAT(fp->uf_name_exp, fp->uf_name + 3);
4911a47ae32SBram Moolenaar }
4921a47ae32SBram Moolenaar }
4931a47ae32SBram Moolenaar }
4941a47ae32SBram Moolenaar
49558016448SBram Moolenaar /*
49604b12697SBram Moolenaar * Get a name for a lambda. Returned in static memory.
49704b12697SBram Moolenaar */
49804b12697SBram Moolenaar char_u *
get_lambda_name(void)49904b12697SBram Moolenaar get_lambda_name(void)
50004b12697SBram Moolenaar {
50104b12697SBram Moolenaar static char_u name[30];
50204b12697SBram Moolenaar static int lambda_no = 0;
50304b12697SBram Moolenaar
50404b12697SBram Moolenaar sprintf((char*)name, "<lambda>%d", ++lambda_no);
50504b12697SBram Moolenaar return name;
50604b12697SBram Moolenaar }
50704b12697SBram Moolenaar
508801ab069SBram Moolenaar #if defined(FEAT_LUA) || defined(PROTO)
509801ab069SBram Moolenaar /*
510801ab069SBram Moolenaar * Registers a native C callback which can be called from Vim script.
511801ab069SBram Moolenaar * Returns the name of the Vim script function.
512801ab069SBram Moolenaar */
513801ab069SBram Moolenaar char_u *
register_cfunc(cfunc_T cb,cfunc_free_T cb_free,void * state)514801ab069SBram Moolenaar register_cfunc(cfunc_T cb, cfunc_free_T cb_free, void *state)
515801ab069SBram Moolenaar {
516801ab069SBram Moolenaar char_u *name = get_lambda_name();
5177d2ac92eSBram Moolenaar ufunc_T *fp;
518801ab069SBram Moolenaar
519801ab069SBram Moolenaar fp = alloc_clear(offsetof(ufunc_T, uf_name) + STRLEN(name) + 1);
520801ab069SBram Moolenaar if (fp == NULL)
5217d2ac92eSBram Moolenaar return NULL;
522801ab069SBram Moolenaar
52338ddf333SBram Moolenaar fp->uf_def_status = UF_NOT_COMPILED;
524801ab069SBram Moolenaar fp->uf_refcount = 1;
525801ab069SBram Moolenaar fp->uf_varargs = TRUE;
526801ab069SBram Moolenaar fp->uf_flags = FC_CFUNC;
527801ab069SBram Moolenaar fp->uf_calls = 0;
528801ab069SBram Moolenaar fp->uf_script_ctx = current_sctx;
529801ab069SBram Moolenaar fp->uf_cb = cb;
530801ab069SBram Moolenaar fp->uf_cb_free = cb_free;
531801ab069SBram Moolenaar fp->uf_cb_state = state;
532801ab069SBram Moolenaar
533801ab069SBram Moolenaar set_ufunc_name(fp, name);
534801ab069SBram Moolenaar hash_add(&func_hashtab, UF2HIKEY(fp));
535801ab069SBram Moolenaar
536801ab069SBram Moolenaar return name;
537801ab069SBram Moolenaar }
538801ab069SBram Moolenaar #endif
539801ab069SBram Moolenaar
54004b12697SBram Moolenaar /*
54165c44152SBram Moolenaar * Skip over "->" or "=>" after the arguments of a lambda.
5429e68c325SBram Moolenaar * If ": type" is found make "ret_type" point to "type".
543c754b4ccSBram Moolenaar * If "white_error" is not NULL check for correct use of white space and set
544c754b4ccSBram Moolenaar * "white_error" to TRUE if there is an error.
54565c44152SBram Moolenaar * Return NULL if no valid arrow found.
54665c44152SBram Moolenaar */
54765c44152SBram Moolenaar static char_u *
skip_arrow(char_u * start,int equal_arrow,char_u ** ret_type,int * white_error)548c754b4ccSBram Moolenaar skip_arrow(
549c754b4ccSBram Moolenaar char_u *start,
550c754b4ccSBram Moolenaar int equal_arrow,
551c754b4ccSBram Moolenaar char_u **ret_type,
552c754b4ccSBram Moolenaar int *white_error)
55365c44152SBram Moolenaar {
55465c44152SBram Moolenaar char_u *s = start;
555c754b4ccSBram Moolenaar char_u *bef = start - 2; // "start" points to > of ->
55665c44152SBram Moolenaar
55765c44152SBram Moolenaar if (equal_arrow)
55865c44152SBram Moolenaar {
55965c44152SBram Moolenaar if (*s == ':')
5609e68c325SBram Moolenaar {
561c754b4ccSBram Moolenaar if (white_error != NULL && !VIM_ISWHITE(s[1]))
562c754b4ccSBram Moolenaar {
563c754b4ccSBram Moolenaar *white_error = TRUE;
564c3fc75dbSBram Moolenaar semsg(_(e_white_space_required_after_str_str), ":", s);
565c754b4ccSBram Moolenaar return NULL;
566c754b4ccSBram Moolenaar }
5679e68c325SBram Moolenaar s = skipwhite(s + 1);
5689e68c325SBram Moolenaar *ret_type = s;
5699e68c325SBram Moolenaar s = skip_type(s, TRUE);
5700346b799SBram Moolenaar if (s == *ret_type)
5710346b799SBram Moolenaar {
5720346b799SBram Moolenaar emsg(_(e_missing_return_type));
5730346b799SBram Moolenaar return NULL;
5740346b799SBram Moolenaar }
5759e68c325SBram Moolenaar }
576c754b4ccSBram Moolenaar bef = s;
57765c44152SBram Moolenaar s = skipwhite(s);
57865c44152SBram Moolenaar if (*s != '=')
57965c44152SBram Moolenaar return NULL;
58065c44152SBram Moolenaar ++s;
58165c44152SBram Moolenaar }
58265c44152SBram Moolenaar if (*s != '>')
58365c44152SBram Moolenaar return NULL;
584c754b4ccSBram Moolenaar if (white_error != NULL && ((!VIM_ISWHITE(*bef) && *bef != '{')
585c754b4ccSBram Moolenaar || !IS_WHITE_OR_NUL(s[1])))
586c754b4ccSBram Moolenaar {
587c754b4ccSBram Moolenaar *white_error = TRUE;
588e7a73e07SBram Moolenaar semsg(_(e_white_space_required_before_and_after_str_at_str),
589e7a73e07SBram Moolenaar equal_arrow ? "=>" : "->", bef);
590c754b4ccSBram Moolenaar return NULL;
591c754b4ccSBram Moolenaar }
59265c44152SBram Moolenaar return skipwhite(s + 1);
59365c44152SBram Moolenaar }
59465c44152SBram Moolenaar
59565c44152SBram Moolenaar /*
5967a6eaa06SBram Moolenaar * Check if "*cmd" points to a function command and if so advance "*cmd" and
5977a6eaa06SBram Moolenaar * return TRUE.
5987a6eaa06SBram Moolenaar * Otherwise return FALSE;
5997a6eaa06SBram Moolenaar * Do not consider "function(" to be a command.
6007a6eaa06SBram Moolenaar */
6017a6eaa06SBram Moolenaar static int
is_function_cmd(char_u ** cmd)6027a6eaa06SBram Moolenaar is_function_cmd(char_u **cmd)
6037a6eaa06SBram Moolenaar {
6047a6eaa06SBram Moolenaar char_u *p = *cmd;
6057a6eaa06SBram Moolenaar
6067a6eaa06SBram Moolenaar if (checkforcmd(&p, "function", 2))
6077a6eaa06SBram Moolenaar {
6087a6eaa06SBram Moolenaar if (*p == '(')
6097a6eaa06SBram Moolenaar return FALSE;
6107a6eaa06SBram Moolenaar *cmd = p;
6117a6eaa06SBram Moolenaar return TRUE;
6127a6eaa06SBram Moolenaar }
6137a6eaa06SBram Moolenaar return FALSE;
6147a6eaa06SBram Moolenaar }
6157a6eaa06SBram Moolenaar
6167a6eaa06SBram Moolenaar /*
6172eb6fc3bSBram Moolenaar * Called when defining a function: The context may be needed for script
6182eb6fc3bSBram Moolenaar * variables declared in a block that is visible now but not when the function
6192eb6fc3bSBram Moolenaar * is compiled or called later.
6202eb6fc3bSBram Moolenaar */
6212eb6fc3bSBram Moolenaar static void
function_using_block_scopes(ufunc_T * fp,cstack_T * cstack)6222eb6fc3bSBram Moolenaar function_using_block_scopes(ufunc_T *fp, cstack_T *cstack)
6232eb6fc3bSBram Moolenaar {
6242eb6fc3bSBram Moolenaar if (cstack != NULL && cstack->cs_idx >= 0)
6252eb6fc3bSBram Moolenaar {
6262eb6fc3bSBram Moolenaar int count = cstack->cs_idx + 1;
6272eb6fc3bSBram Moolenaar int i;
6282eb6fc3bSBram Moolenaar
6292eb6fc3bSBram Moolenaar fp->uf_block_ids = ALLOC_MULT(int, count);
6302eb6fc3bSBram Moolenaar if (fp->uf_block_ids != NULL)
6312eb6fc3bSBram Moolenaar {
6322eb6fc3bSBram Moolenaar mch_memmove(fp->uf_block_ids, cstack->cs_block_id,
6332eb6fc3bSBram Moolenaar sizeof(int) * count);
6342eb6fc3bSBram Moolenaar fp->uf_block_depth = count;
6352eb6fc3bSBram Moolenaar }
6362eb6fc3bSBram Moolenaar
6372eb6fc3bSBram Moolenaar // Set flag in each block to indicate a function was defined. This
6382eb6fc3bSBram Moolenaar // is used to keep the variable when leaving the block, see
6392eb6fc3bSBram Moolenaar // hide_script_var().
6402eb6fc3bSBram Moolenaar for (i = 0; i <= cstack->cs_idx; ++i)
6412eb6fc3bSBram Moolenaar cstack->cs_flags[i] |= CSF_FUNC_DEF;
6422eb6fc3bSBram Moolenaar }
6432eb6fc3bSBram Moolenaar }
6442eb6fc3bSBram Moolenaar
6452eb6fc3bSBram Moolenaar /*
6467a6eaa06SBram Moolenaar * Read the body of a function, put every line in "newlines".
647074f84c0SBram Moolenaar * This stops at "}", "endfunction" or "enddef".
6487a6eaa06SBram Moolenaar * "newlines" must already have been initialized.
6497a6eaa06SBram Moolenaar * "eap->cmdidx" is CMD_function, CMD_def or CMD_block;
6507a6eaa06SBram Moolenaar */
6517a6eaa06SBram Moolenaar static int
get_function_body(exarg_T * eap,garray_T * newlines,char_u * line_arg_in,char_u ** line_to_free)6527a6eaa06SBram Moolenaar get_function_body(
6537a6eaa06SBram Moolenaar exarg_T *eap,
6547a6eaa06SBram Moolenaar garray_T *newlines,
6557a6eaa06SBram Moolenaar char_u *line_arg_in,
6567a6eaa06SBram Moolenaar char_u **line_to_free)
6577a6eaa06SBram Moolenaar {
6587a6eaa06SBram Moolenaar linenr_T sourcing_lnum_top = SOURCING_LNUM;
6597a6eaa06SBram Moolenaar linenr_T sourcing_lnum_off;
6607a6eaa06SBram Moolenaar int saved_wait_return = need_wait_return;
6617a6eaa06SBram Moolenaar char_u *line_arg = line_arg_in;
6627a6eaa06SBram Moolenaar int vim9_function = eap->cmdidx == CMD_def
6637a6eaa06SBram Moolenaar || eap->cmdidx == CMD_block;
6647a6eaa06SBram Moolenaar #define MAX_FUNC_NESTING 50
6657a6eaa06SBram Moolenaar char nesting_def[MAX_FUNC_NESTING];
6665245beb3SBram Moolenaar char nesting_inline[MAX_FUNC_NESTING];
6677a6eaa06SBram Moolenaar int nesting = 0;
6687a6eaa06SBram Moolenaar getline_opt_T getline_options;
6697a6eaa06SBram Moolenaar int indent = 2;
6707a6eaa06SBram Moolenaar char_u *skip_until = NULL;
6717a6eaa06SBram Moolenaar int ret = FAIL;
6727a6eaa06SBram Moolenaar int is_heredoc = FALSE;
6732067733bSBram Moolenaar int heredoc_concat_len = 0;
6742067733bSBram Moolenaar garray_T heredoc_ga;
6757a6eaa06SBram Moolenaar char_u *heredoc_trimmed = NULL;
6767a6eaa06SBram Moolenaar
6772067733bSBram Moolenaar ga_init2(&heredoc_ga, 1, 500);
6782067733bSBram Moolenaar
6797a6eaa06SBram Moolenaar // Detect having skipped over comment lines to find the return
6807a6eaa06SBram Moolenaar // type. Add NULL lines to keep the line count correct.
6817a6eaa06SBram Moolenaar sourcing_lnum_off = get_sourced_lnum(eap->getline, eap->cookie);
6827a6eaa06SBram Moolenaar if (SOURCING_LNUM < sourcing_lnum_off)
6837a6eaa06SBram Moolenaar {
6847a6eaa06SBram Moolenaar sourcing_lnum_off -= SOURCING_LNUM;
6857a6eaa06SBram Moolenaar if (ga_grow(newlines, sourcing_lnum_off) == FAIL)
6867a6eaa06SBram Moolenaar goto theend;
6877a6eaa06SBram Moolenaar while (sourcing_lnum_off-- > 0)
6887a6eaa06SBram Moolenaar ((char_u **)(newlines->ga_data))[newlines->ga_len++] = NULL;
6897a6eaa06SBram Moolenaar }
6907a6eaa06SBram Moolenaar
6915245beb3SBram Moolenaar nesting_def[0] = vim9_function;
6925245beb3SBram Moolenaar nesting_inline[0] = eap->cmdidx == CMD_block;
6937a6eaa06SBram Moolenaar getline_options = vim9_function
6947a6eaa06SBram Moolenaar ? GETLINE_CONCAT_CONTBAR : GETLINE_CONCAT_CONT;
6957a6eaa06SBram Moolenaar for (;;)
6967a6eaa06SBram Moolenaar {
6977a6eaa06SBram Moolenaar char_u *theline;
6987a6eaa06SBram Moolenaar char_u *p;
6997a6eaa06SBram Moolenaar char_u *arg;
7007a6eaa06SBram Moolenaar
7017a6eaa06SBram Moolenaar if (KeyTyped)
7027a6eaa06SBram Moolenaar {
7037a6eaa06SBram Moolenaar msg_scroll = TRUE;
7047a6eaa06SBram Moolenaar saved_wait_return = FALSE;
7057a6eaa06SBram Moolenaar }
7067a6eaa06SBram Moolenaar need_wait_return = FALSE;
7077a6eaa06SBram Moolenaar
7087a6eaa06SBram Moolenaar if (line_arg != NULL)
7097a6eaa06SBram Moolenaar {
7107a6eaa06SBram Moolenaar // Use eap->arg, split up in parts by line breaks.
7117a6eaa06SBram Moolenaar theline = line_arg;
7127a6eaa06SBram Moolenaar p = vim_strchr(theline, '\n');
7137a6eaa06SBram Moolenaar if (p == NULL)
7147a6eaa06SBram Moolenaar line_arg += STRLEN(line_arg);
7157a6eaa06SBram Moolenaar else
7167a6eaa06SBram Moolenaar {
7177a6eaa06SBram Moolenaar *p = NUL;
7187a6eaa06SBram Moolenaar line_arg = p + 1;
7197a6eaa06SBram Moolenaar }
7207a6eaa06SBram Moolenaar }
7217a6eaa06SBram Moolenaar else
7227a6eaa06SBram Moolenaar {
7237a6eaa06SBram Moolenaar vim_free(*line_to_free);
7247a6eaa06SBram Moolenaar if (eap->getline == NULL)
7257a6eaa06SBram Moolenaar theline = getcmdline(':', 0L, indent, getline_options);
7267a6eaa06SBram Moolenaar else
7277a6eaa06SBram Moolenaar theline = eap->getline(':', eap->cookie, indent,
7287a6eaa06SBram Moolenaar getline_options);
7297a6eaa06SBram Moolenaar *line_to_free = theline;
7307a6eaa06SBram Moolenaar }
7317a6eaa06SBram Moolenaar if (KeyTyped)
7327a6eaa06SBram Moolenaar lines_left = Rows - 1;
7337a6eaa06SBram Moolenaar if (theline == NULL)
7347a6eaa06SBram Moolenaar {
7357a6eaa06SBram Moolenaar // Use the start of the function for the line number.
7367a6eaa06SBram Moolenaar SOURCING_LNUM = sourcing_lnum_top;
7377a6eaa06SBram Moolenaar if (skip_until != NULL)
7387a6eaa06SBram Moolenaar semsg(_(e_missing_heredoc_end_marker_str), skip_until);
7395245beb3SBram Moolenaar else if (nesting_inline[nesting])
7405245beb3SBram Moolenaar emsg(_(e_missing_end_block));
7417a6eaa06SBram Moolenaar else if (eap->cmdidx == CMD_def)
7427a6eaa06SBram Moolenaar emsg(_(e_missing_enddef));
7437a6eaa06SBram Moolenaar else
7447a6eaa06SBram Moolenaar emsg(_("E126: Missing :endfunction"));
7457a6eaa06SBram Moolenaar goto theend;
7467a6eaa06SBram Moolenaar }
7477a6eaa06SBram Moolenaar
7487a6eaa06SBram Moolenaar // Detect line continuation: SOURCING_LNUM increased more than one.
7497a6eaa06SBram Moolenaar sourcing_lnum_off = get_sourced_lnum(eap->getline, eap->cookie);
7507a6eaa06SBram Moolenaar if (SOURCING_LNUM < sourcing_lnum_off)
7517a6eaa06SBram Moolenaar sourcing_lnum_off -= SOURCING_LNUM;
7527a6eaa06SBram Moolenaar else
7537a6eaa06SBram Moolenaar sourcing_lnum_off = 0;
7547a6eaa06SBram Moolenaar
7557a6eaa06SBram Moolenaar if (skip_until != NULL)
7567a6eaa06SBram Moolenaar {
7577a6eaa06SBram Moolenaar // Don't check for ":endfunc"/":enddef" between
7587a6eaa06SBram Moolenaar // * ":append" and "."
7597a6eaa06SBram Moolenaar // * ":python <<EOF" and "EOF"
7607a6eaa06SBram Moolenaar // * ":let {var-name} =<< [trim] {marker}" and "{marker}"
7617a6eaa06SBram Moolenaar if (heredoc_trimmed == NULL
7627a6eaa06SBram Moolenaar || (is_heredoc && skipwhite(theline) == theline)
7637a6eaa06SBram Moolenaar || STRNCMP(theline, heredoc_trimmed,
7647a6eaa06SBram Moolenaar STRLEN(heredoc_trimmed)) == 0)
7657a6eaa06SBram Moolenaar {
7667a6eaa06SBram Moolenaar if (heredoc_trimmed == NULL)
7677a6eaa06SBram Moolenaar p = theline;
7687a6eaa06SBram Moolenaar else if (is_heredoc)
7697a6eaa06SBram Moolenaar p = skipwhite(theline) == theline
7707a6eaa06SBram Moolenaar ? theline : theline + STRLEN(heredoc_trimmed);
7717a6eaa06SBram Moolenaar else
7727a6eaa06SBram Moolenaar p = theline + STRLEN(heredoc_trimmed);
7737a6eaa06SBram Moolenaar if (STRCMP(p, skip_until) == 0)
7747a6eaa06SBram Moolenaar {
7757a6eaa06SBram Moolenaar VIM_CLEAR(skip_until);
7767a6eaa06SBram Moolenaar VIM_CLEAR(heredoc_trimmed);
7777a6eaa06SBram Moolenaar getline_options = vim9_function
7787a6eaa06SBram Moolenaar ? GETLINE_CONCAT_CONTBAR : GETLINE_CONCAT_CONT;
7797a6eaa06SBram Moolenaar is_heredoc = FALSE;
7802067733bSBram Moolenaar
7812067733bSBram Moolenaar if (heredoc_concat_len > 0)
7822067733bSBram Moolenaar {
7832067733bSBram Moolenaar // Replace the starting line with all the concatenated
7842067733bSBram Moolenaar // lines.
7852067733bSBram Moolenaar ga_concat(&heredoc_ga, theline);
7862067733bSBram Moolenaar vim_free(((char_u **)(newlines->ga_data))[
7872067733bSBram Moolenaar heredoc_concat_len - 1]);
7882067733bSBram Moolenaar ((char_u **)(newlines->ga_data))[
7892067733bSBram Moolenaar heredoc_concat_len - 1] = heredoc_ga.ga_data;
7902067733bSBram Moolenaar ga_init(&heredoc_ga);
7912067733bSBram Moolenaar heredoc_concat_len = 0;
7922067733bSBram Moolenaar theline += STRLEN(theline); // skip the "EOF"
7932067733bSBram Moolenaar }
7947a6eaa06SBram Moolenaar }
7957a6eaa06SBram Moolenaar }
7967a6eaa06SBram Moolenaar }
7977a6eaa06SBram Moolenaar else
7987a6eaa06SBram Moolenaar {
7997a6eaa06SBram Moolenaar int c;
8005245beb3SBram Moolenaar char_u *end;
8017a6eaa06SBram Moolenaar
8027a6eaa06SBram Moolenaar // skip ':' and blanks
8037a6eaa06SBram Moolenaar for (p = theline; VIM_ISWHITE(*p) || *p == ':'; ++p)
8047a6eaa06SBram Moolenaar ;
8057a6eaa06SBram Moolenaar
8067a6eaa06SBram Moolenaar // Check for "endfunction", "enddef" or "}".
8077a6eaa06SBram Moolenaar // When a ":" follows it must be a dict key; "enddef: value,"
8085245beb3SBram Moolenaar if (nesting_inline[nesting]
8097a6eaa06SBram Moolenaar ? *p == '}'
8107a6eaa06SBram Moolenaar : (checkforcmd(&p, nesting_def[nesting]
8117a6eaa06SBram Moolenaar ? "enddef" : "endfunction", 4)
8127a6eaa06SBram Moolenaar && *p != ':'))
8137a6eaa06SBram Moolenaar {
8147a6eaa06SBram Moolenaar if (nesting-- == 0)
8157a6eaa06SBram Moolenaar {
8167a6eaa06SBram Moolenaar char_u *nextcmd = NULL;
8177a6eaa06SBram Moolenaar
8187a6eaa06SBram Moolenaar if (*p == '|' || *p == '}')
8197a6eaa06SBram Moolenaar nextcmd = p + 1;
8207a6eaa06SBram Moolenaar else if (line_arg != NULL && *skipwhite(line_arg) != NUL)
8217a6eaa06SBram Moolenaar nextcmd = line_arg;
8227a6eaa06SBram Moolenaar else if (*p != NUL && *p != (vim9_function ? '#' : '"')
82349f1e9ecSBram Moolenaar && (vim9_function || p_verbose > 0))
82449f1e9ecSBram Moolenaar {
8254bba16d2SBram Moolenaar SOURCING_LNUM = sourcing_lnum_top
8264bba16d2SBram Moolenaar + newlines->ga_len + 1;
82749f1e9ecSBram Moolenaar if (eap->cmdidx == CMD_def)
82849f1e9ecSBram Moolenaar semsg(_(e_text_found_after_enddef_str), p);
82949f1e9ecSBram Moolenaar else
83049f1e9ecSBram Moolenaar give_warning2((char_u *)
83149f1e9ecSBram Moolenaar _("W22: Text found after :endfunction: %s"),
8327a6eaa06SBram Moolenaar p, TRUE);
83349f1e9ecSBram Moolenaar }
83449f1e9ecSBram Moolenaar if (nextcmd != NULL && *skipwhite(nextcmd) != NUL)
8357a6eaa06SBram Moolenaar {
8367a6eaa06SBram Moolenaar // Another command follows. If the line came from "eap"
8377a6eaa06SBram Moolenaar // we can simply point into it, otherwise we need to
8387a6eaa06SBram Moolenaar // change "eap->cmdlinep".
8397a6eaa06SBram Moolenaar eap->nextcmd = nextcmd;
8407a6eaa06SBram Moolenaar if (*line_to_free != NULL)
8417a6eaa06SBram Moolenaar {
8427a6eaa06SBram Moolenaar vim_free(*eap->cmdlinep);
8437a6eaa06SBram Moolenaar *eap->cmdlinep = *line_to_free;
8447a6eaa06SBram Moolenaar *line_to_free = NULL;
8457a6eaa06SBram Moolenaar }
8467a6eaa06SBram Moolenaar }
8477a6eaa06SBram Moolenaar break;
8487a6eaa06SBram Moolenaar }
8497a6eaa06SBram Moolenaar }
8507a6eaa06SBram Moolenaar
8517a6eaa06SBram Moolenaar // Check for mismatched "endfunc" or "enddef".
8527a6eaa06SBram Moolenaar // We don't check for "def" inside "func" thus we also can't check
8537a6eaa06SBram Moolenaar // for "enddef".
8547a6eaa06SBram Moolenaar // We continue to find the end of the function, although we might
8557a6eaa06SBram Moolenaar // not find it.
8567a6eaa06SBram Moolenaar else if (nesting_def[nesting])
8577a6eaa06SBram Moolenaar {
8587a6eaa06SBram Moolenaar if (checkforcmd(&p, "endfunction", 4) && *p != ':')
8597a6eaa06SBram Moolenaar emsg(_(e_mismatched_endfunction));
8607a6eaa06SBram Moolenaar }
8617a6eaa06SBram Moolenaar else if (eap->cmdidx == CMD_def && checkforcmd(&p, "enddef", 4))
8627a6eaa06SBram Moolenaar emsg(_(e_mismatched_enddef));
8637a6eaa06SBram Moolenaar
8647a6eaa06SBram Moolenaar // Increase indent inside "if", "while", "for" and "try", decrease
8657a6eaa06SBram Moolenaar // at "end".
8667a6eaa06SBram Moolenaar if (indent > 2 && (*p == '}' || STRNCMP(p, "end", 3) == 0))
8677a6eaa06SBram Moolenaar indent -= 2;
8687a6eaa06SBram Moolenaar else if (STRNCMP(p, "if", 2) == 0
8697a6eaa06SBram Moolenaar || STRNCMP(p, "wh", 2) == 0
8707a6eaa06SBram Moolenaar || STRNCMP(p, "for", 3) == 0
8717a6eaa06SBram Moolenaar || STRNCMP(p, "try", 3) == 0)
8727a6eaa06SBram Moolenaar indent += 2;
8737a6eaa06SBram Moolenaar
8747a6eaa06SBram Moolenaar // Check for defining a function inside this function.
8757a6eaa06SBram Moolenaar // Only recognize "def" inside "def", not inside "function",
8767a6eaa06SBram Moolenaar // For backwards compatibility, see Test_function_python().
8777a6eaa06SBram Moolenaar c = *p;
8787a6eaa06SBram Moolenaar if (is_function_cmd(&p)
8797a6eaa06SBram Moolenaar || (eap->cmdidx == CMD_def && checkforcmd(&p, "def", 3)))
8807a6eaa06SBram Moolenaar {
8817a6eaa06SBram Moolenaar if (*p == '!')
8827a6eaa06SBram Moolenaar p = skipwhite(p + 1);
8837a6eaa06SBram Moolenaar p += eval_fname_script(p);
8847a6eaa06SBram Moolenaar vim_free(trans_function_name(&p, NULL, TRUE, 0, NULL,
8857a6eaa06SBram Moolenaar NULL, NULL));
8867a6eaa06SBram Moolenaar if (*skipwhite(p) == '(')
8877a6eaa06SBram Moolenaar {
8887a6eaa06SBram Moolenaar if (nesting == MAX_FUNC_NESTING - 1)
8897a6eaa06SBram Moolenaar emsg(_(e_function_nesting_too_deep));
8907a6eaa06SBram Moolenaar else
8917a6eaa06SBram Moolenaar {
8927a6eaa06SBram Moolenaar ++nesting;
8937a6eaa06SBram Moolenaar nesting_def[nesting] = (c == 'd');
8945245beb3SBram Moolenaar nesting_inline[nesting] = FALSE;
8955245beb3SBram Moolenaar indent += 2;
8965245beb3SBram Moolenaar }
8975245beb3SBram Moolenaar }
8985245beb3SBram Moolenaar }
8995245beb3SBram Moolenaar
900ac2cd2b0SBram Moolenaar if (nesting_def[nesting] ? *p != '#' : *p != '"')
901ac2cd2b0SBram Moolenaar {
902ac2cd2b0SBram Moolenaar // Not a comment line: check for nested inline function.
9035245beb3SBram Moolenaar end = p + STRLEN(p) - 1;
9045245beb3SBram Moolenaar while (end > p && VIM_ISWHITE(*end))
9055245beb3SBram Moolenaar --end;
90613212573SBram Moolenaar if (end > p + 1 && *end == '{' && VIM_ISWHITE(end[-1]))
9075245beb3SBram Moolenaar {
908e4db17fbSBram Moolenaar int is_block;
909e4db17fbSBram Moolenaar
910e4db17fbSBram Moolenaar // check for trailing "=> {": start of an inline function
9115245beb3SBram Moolenaar --end;
9125245beb3SBram Moolenaar while (end > p && VIM_ISWHITE(*end))
9135245beb3SBram Moolenaar --end;
914e4db17fbSBram Moolenaar is_block = end > p + 2 && end[-1] == '=' && end[0] == '>';
915e4db17fbSBram Moolenaar if (!is_block)
9165245beb3SBram Moolenaar {
917e4db17fbSBram Moolenaar char_u *s = p;
918e4db17fbSBram Moolenaar
919e4db17fbSBram Moolenaar // check for line starting with "au" for :autocmd or
920e4db17fbSBram Moolenaar // "com" for :command, these can use a {} block
921e4db17fbSBram Moolenaar is_block = checkforcmd_noparen(&s, "autocmd", 2)
922e4db17fbSBram Moolenaar || checkforcmd_noparen(&s, "command", 3);
923e4db17fbSBram Moolenaar }
924e4db17fbSBram Moolenaar
925e4db17fbSBram Moolenaar if (is_block)
926e4db17fbSBram Moolenaar {
9275245beb3SBram Moolenaar if (nesting == MAX_FUNC_NESTING - 1)
9285245beb3SBram Moolenaar emsg(_(e_function_nesting_too_deep));
9295245beb3SBram Moolenaar else
9305245beb3SBram Moolenaar {
9315245beb3SBram Moolenaar ++nesting;
9325245beb3SBram Moolenaar nesting_def[nesting] = TRUE;
9335245beb3SBram Moolenaar nesting_inline[nesting] = TRUE;
9347a6eaa06SBram Moolenaar indent += 2;
9357a6eaa06SBram Moolenaar }
9367a6eaa06SBram Moolenaar }
9377a6eaa06SBram Moolenaar }
938ac2cd2b0SBram Moolenaar }
9397a6eaa06SBram Moolenaar
9407a6eaa06SBram Moolenaar // Check for ":append", ":change", ":insert". Not for :def.
9417a6eaa06SBram Moolenaar p = skip_range(p, FALSE, NULL);
9427a6eaa06SBram Moolenaar if (!vim9_function
9437a6eaa06SBram Moolenaar && ((p[0] == 'a' && (!ASCII_ISALPHA(p[1]) || p[1] == 'p'))
9447a6eaa06SBram Moolenaar || (p[0] == 'c'
9457a6eaa06SBram Moolenaar && (!ASCII_ISALPHA(p[1]) || (p[1] == 'h'
9467a6eaa06SBram Moolenaar && (!ASCII_ISALPHA(p[2]) || (p[2] == 'a'
9477a6eaa06SBram Moolenaar && (STRNCMP(&p[3], "nge", 3) != 0
9487a6eaa06SBram Moolenaar || !ASCII_ISALPHA(p[6])))))))
9497a6eaa06SBram Moolenaar || (p[0] == 'i'
9507a6eaa06SBram Moolenaar && (!ASCII_ISALPHA(p[1]) || (p[1] == 'n'
9517a6eaa06SBram Moolenaar && (!ASCII_ISALPHA(p[2])
9527a6eaa06SBram Moolenaar || (p[2] == 's'
9537a6eaa06SBram Moolenaar && (!ASCII_ISALPHA(p[3])
9547a6eaa06SBram Moolenaar || p[3] == 'e'))))))))
9557a6eaa06SBram Moolenaar skip_until = vim_strsave((char_u *)".");
9567a6eaa06SBram Moolenaar
9577a6eaa06SBram Moolenaar // Check for ":python <<EOF", ":tcl <<EOF", etc.
9587a6eaa06SBram Moolenaar arg = skipwhite(skiptowhite(p));
9597a6eaa06SBram Moolenaar if (arg[0] == '<' && arg[1] =='<'
9607a6eaa06SBram Moolenaar && ((p[0] == 'p' && p[1] == 'y'
9617a6eaa06SBram Moolenaar && (!ASCII_ISALNUM(p[2]) || p[2] == 't'
9627a6eaa06SBram Moolenaar || ((p[2] == '3' || p[2] == 'x')
9637a6eaa06SBram Moolenaar && !ASCII_ISALPHA(p[3]))))
9647a6eaa06SBram Moolenaar || (p[0] == 'p' && p[1] == 'e'
9657a6eaa06SBram Moolenaar && (!ASCII_ISALPHA(p[2]) || p[2] == 'r'))
9667a6eaa06SBram Moolenaar || (p[0] == 't' && p[1] == 'c'
9677a6eaa06SBram Moolenaar && (!ASCII_ISALPHA(p[2]) || p[2] == 'l'))
9687a6eaa06SBram Moolenaar || (p[0] == 'l' && p[1] == 'u' && p[2] == 'a'
9697a6eaa06SBram Moolenaar && !ASCII_ISALPHA(p[3]))
9707a6eaa06SBram Moolenaar || (p[0] == 'r' && p[1] == 'u' && p[2] == 'b'
9717a6eaa06SBram Moolenaar && (!ASCII_ISALPHA(p[3]) || p[3] == 'y'))
9727a6eaa06SBram Moolenaar || (p[0] == 'm' && p[1] == 'z'
9737a6eaa06SBram Moolenaar && (!ASCII_ISALPHA(p[2]) || p[2] == 's'))
9747a6eaa06SBram Moolenaar ))
9757a6eaa06SBram Moolenaar {
9767a6eaa06SBram Moolenaar // ":python <<" continues until a dot, like ":append"
9777a6eaa06SBram Moolenaar p = skipwhite(arg + 2);
9787a6eaa06SBram Moolenaar if (STRNCMP(p, "trim", 4) == 0)
9797a6eaa06SBram Moolenaar {
9807a6eaa06SBram Moolenaar // Ignore leading white space.
9817a6eaa06SBram Moolenaar p = skipwhite(p + 4);
9827a6eaa06SBram Moolenaar heredoc_trimmed = vim_strnsave(theline,
9837a6eaa06SBram Moolenaar skipwhite(theline) - theline);
9847a6eaa06SBram Moolenaar }
9857a6eaa06SBram Moolenaar if (*p == NUL)
9867a6eaa06SBram Moolenaar skip_until = vim_strsave((char_u *)".");
9877a6eaa06SBram Moolenaar else
9887a6eaa06SBram Moolenaar skip_until = vim_strnsave(p, skiptowhite(p) - p);
9897a6eaa06SBram Moolenaar getline_options = GETLINE_NONE;
9907a6eaa06SBram Moolenaar is_heredoc = TRUE;
9912067733bSBram Moolenaar if (eap->cmdidx == CMD_def)
9922067733bSBram Moolenaar heredoc_concat_len = newlines->ga_len + 1;
9937a6eaa06SBram Moolenaar }
9947a6eaa06SBram Moolenaar
9957a6eaa06SBram Moolenaar // Check for ":cmd v =<< [trim] EOF"
9967a6eaa06SBram Moolenaar // and ":cmd [a, b] =<< [trim] EOF"
9977a6eaa06SBram Moolenaar // and "lines =<< [trim] EOF" for Vim9
9987a6eaa06SBram Moolenaar // Where "cmd" can be "let", "var", "final" or "const".
9997a6eaa06SBram Moolenaar arg = skipwhite(skiptowhite(p));
10007a6eaa06SBram Moolenaar if (*arg == '[')
10017a6eaa06SBram Moolenaar arg = vim_strchr(arg, ']');
10027a6eaa06SBram Moolenaar if (arg != NULL)
10037a6eaa06SBram Moolenaar {
10047a6eaa06SBram Moolenaar int found = (eap->cmdidx == CMD_def && arg[0] == '='
10057a6eaa06SBram Moolenaar && arg[1] == '<' && arg[2] =='<');
10067a6eaa06SBram Moolenaar
10077a6eaa06SBram Moolenaar if (!found)
10087a6eaa06SBram Moolenaar // skip over the argument after "cmd"
10097a6eaa06SBram Moolenaar arg = skipwhite(skiptowhite(arg));
10107a6eaa06SBram Moolenaar if (found || (arg[0] == '=' && arg[1] == '<' && arg[2] =='<'
10117a6eaa06SBram Moolenaar && (checkforcmd(&p, "let", 2)
10127a6eaa06SBram Moolenaar || checkforcmd(&p, "var", 3)
10137a6eaa06SBram Moolenaar || checkforcmd(&p, "final", 5)
10147a6eaa06SBram Moolenaar || checkforcmd(&p, "const", 5))))
10157a6eaa06SBram Moolenaar {
10167a6eaa06SBram Moolenaar p = skipwhite(arg + 3);
10177a6eaa06SBram Moolenaar if (STRNCMP(p, "trim", 4) == 0)
10187a6eaa06SBram Moolenaar {
10197a6eaa06SBram Moolenaar // Ignore leading white space.
10207a6eaa06SBram Moolenaar p = skipwhite(p + 4);
10217a6eaa06SBram Moolenaar heredoc_trimmed = vim_strnsave(theline,
10227a6eaa06SBram Moolenaar skipwhite(theline) - theline);
10237a6eaa06SBram Moolenaar }
10247a6eaa06SBram Moolenaar skip_until = vim_strnsave(p, skiptowhite(p) - p);
10257a6eaa06SBram Moolenaar getline_options = GETLINE_NONE;
10267a6eaa06SBram Moolenaar is_heredoc = TRUE;
10277a6eaa06SBram Moolenaar }
10287a6eaa06SBram Moolenaar }
10297a6eaa06SBram Moolenaar }
10307a6eaa06SBram Moolenaar
10317a6eaa06SBram Moolenaar // Add the line to the function.
10327a6eaa06SBram Moolenaar if (ga_grow(newlines, 1 + sourcing_lnum_off) == FAIL)
10337a6eaa06SBram Moolenaar goto theend;
10347a6eaa06SBram Moolenaar
10352067733bSBram Moolenaar if (heredoc_concat_len > 0)
10362067733bSBram Moolenaar {
10372067733bSBram Moolenaar // For a :def function "python << EOF" concatenats all the lines,
10382067733bSBram Moolenaar // to be used for the instruction later.
10392067733bSBram Moolenaar ga_concat(&heredoc_ga, theline);
10402067733bSBram Moolenaar ga_concat(&heredoc_ga, (char_u *)"\n");
10412067733bSBram Moolenaar p = vim_strsave((char_u *)"");
10422067733bSBram Moolenaar }
10432067733bSBram Moolenaar else
10442067733bSBram Moolenaar {
10457a6eaa06SBram Moolenaar // Copy the line to newly allocated memory. get_one_sourceline()
10462067733bSBram Moolenaar // allocates 250 bytes per line, this saves 80% on average. The
10472067733bSBram Moolenaar // cost is an extra alloc/free.
10487a6eaa06SBram Moolenaar p = vim_strsave(theline);
10492067733bSBram Moolenaar }
10507a6eaa06SBram Moolenaar if (p == NULL)
10517a6eaa06SBram Moolenaar goto theend;
10527a6eaa06SBram Moolenaar ((char_u **)(newlines->ga_data))[newlines->ga_len++] = p;
10537a6eaa06SBram Moolenaar
10547a6eaa06SBram Moolenaar // Add NULL lines for continuation lines, so that the line count is
10557a6eaa06SBram Moolenaar // equal to the index in the growarray.
10567a6eaa06SBram Moolenaar while (sourcing_lnum_off-- > 0)
10577a6eaa06SBram Moolenaar ((char_u **)(newlines->ga_data))[newlines->ga_len++] = NULL;
10587a6eaa06SBram Moolenaar
10597a6eaa06SBram Moolenaar // Check for end of eap->arg.
10607a6eaa06SBram Moolenaar if (line_arg != NULL && *line_arg == NUL)
10617a6eaa06SBram Moolenaar line_arg = NULL;
10627a6eaa06SBram Moolenaar }
10637a6eaa06SBram Moolenaar
1064074f84c0SBram Moolenaar // Return OK when no error was detected.
1065074f84c0SBram Moolenaar if (!did_emsg)
10667a6eaa06SBram Moolenaar ret = OK;
10677a6eaa06SBram Moolenaar
10687a6eaa06SBram Moolenaar theend:
10697a6eaa06SBram Moolenaar vim_free(skip_until);
10707a6eaa06SBram Moolenaar vim_free(heredoc_trimmed);
10712067733bSBram Moolenaar vim_free(heredoc_ga.ga_data);
10727a6eaa06SBram Moolenaar need_wait_return |= saved_wait_return;
10737a6eaa06SBram Moolenaar return ret;
10747a6eaa06SBram Moolenaar }
10757a6eaa06SBram Moolenaar
10767a6eaa06SBram Moolenaar /*
10777a6eaa06SBram Moolenaar * Handle the body of a lambda. *arg points to the "{", process statements
10787a6eaa06SBram Moolenaar * until the matching "}".
1079074f84c0SBram Moolenaar * When not evaluating "newargs" is NULL.
10807a6eaa06SBram Moolenaar * When successful "rettv" is set to a funcref.
10817a6eaa06SBram Moolenaar */
10827a6eaa06SBram Moolenaar static int
lambda_function_body(char_u ** arg,typval_T * rettv,evalarg_T * evalarg,garray_T * newargs,garray_T * argtypes,int varargs,garray_T * default_args,char_u * ret_type)10837a6eaa06SBram Moolenaar lambda_function_body(
10847a6eaa06SBram Moolenaar char_u **arg,
10857a6eaa06SBram Moolenaar typval_T *rettv,
10867a6eaa06SBram Moolenaar evalarg_T *evalarg,
10877a6eaa06SBram Moolenaar garray_T *newargs,
10887a6eaa06SBram Moolenaar garray_T *argtypes,
10897a6eaa06SBram Moolenaar int varargs,
10907a6eaa06SBram Moolenaar garray_T *default_args,
10917a6eaa06SBram Moolenaar char_u *ret_type)
10927a6eaa06SBram Moolenaar {
1093fed9e830SBram Moolenaar int evaluate = (evalarg->eval_flags & EVAL_EVALUATE);
1094074f84c0SBram Moolenaar garray_T *gap = &evalarg->eval_ga;
1095ecb66450SBram Moolenaar garray_T *freegap = &evalarg->eval_freega;
109679efa2e3SBram Moolenaar ufunc_T *ufunc = NULL;
10977a6eaa06SBram Moolenaar exarg_T eap;
10987a6eaa06SBram Moolenaar garray_T newlines;
10997a6eaa06SBram Moolenaar char_u *cmdline = NULL;
11007a6eaa06SBram Moolenaar int ret = FAIL;
11017a6eaa06SBram Moolenaar char_u *line_to_free = NULL;
11027a6eaa06SBram Moolenaar partial_T *pt;
11037a6eaa06SBram Moolenaar char_u *name;
11047a6eaa06SBram Moolenaar int lnum_save = -1;
11057a6eaa06SBram Moolenaar linenr_T sourcing_lnum_top = SOURCING_LNUM;
11067a6eaa06SBram Moolenaar
1107e98f60a5SBram Moolenaar if (!ends_excmd2(*arg, skipwhite(*arg + 1)))
1108e98f60a5SBram Moolenaar {
1109e98f60a5SBram Moolenaar semsg(_(e_trailing_arg), *arg + 1);
1110e98f60a5SBram Moolenaar return FAIL;
1111e98f60a5SBram Moolenaar }
1112e98f60a5SBram Moolenaar
11137a6eaa06SBram Moolenaar CLEAR_FIELD(eap);
11147a6eaa06SBram Moolenaar eap.cmdidx = CMD_block;
11157a6eaa06SBram Moolenaar eap.forceit = FALSE;
11167a6eaa06SBram Moolenaar eap.cmdlinep = &cmdline;
11177a6eaa06SBram Moolenaar eap.skip = !evaluate;
11187a6eaa06SBram Moolenaar if (evalarg->eval_cctx != NULL)
11197a6eaa06SBram Moolenaar fill_exarg_from_cctx(&eap, evalarg->eval_cctx);
11207a6eaa06SBram Moolenaar else
11217a6eaa06SBram Moolenaar {
11227a6eaa06SBram Moolenaar eap.getline = evalarg->eval_getline;
11237a6eaa06SBram Moolenaar eap.cookie = evalarg->eval_cookie;
11247a6eaa06SBram Moolenaar }
11257a6eaa06SBram Moolenaar
11267a6eaa06SBram Moolenaar ga_init2(&newlines, (int)sizeof(char_u *), 10);
11277a6eaa06SBram Moolenaar if (get_function_body(&eap, &newlines, NULL, &line_to_free) == FAIL)
112867da21a1SBram Moolenaar {
112967da21a1SBram Moolenaar vim_free(cmdline);
11307a6eaa06SBram Moolenaar goto erret;
113167da21a1SBram Moolenaar }
1132074f84c0SBram Moolenaar
1133074f84c0SBram Moolenaar // When inside a lambda must add the function lines to evalarg.eval_ga.
1134074f84c0SBram Moolenaar evalarg->eval_break_count += newlines.ga_len;
1135074f84c0SBram Moolenaar if (gap->ga_itemsize > 0)
1136074f84c0SBram Moolenaar {
1137074f84c0SBram Moolenaar int idx;
1138074f84c0SBram Moolenaar char_u *last;
1139074f84c0SBram Moolenaar size_t plen;
1140074f84c0SBram Moolenaar char_u *pnl;
1141074f84c0SBram Moolenaar
1142074f84c0SBram Moolenaar for (idx = 0; idx < newlines.ga_len; ++idx)
1143074f84c0SBram Moolenaar {
1144074f84c0SBram Moolenaar char_u *p = skipwhite(((char_u **)newlines.ga_data)[idx]);
1145074f84c0SBram Moolenaar
1146ecb66450SBram Moolenaar if (ga_grow(gap, 1) == FAIL || ga_grow(freegap, 1) == FAIL)
1147074f84c0SBram Moolenaar goto erret;
1148074f84c0SBram Moolenaar
1149074f84c0SBram Moolenaar // Going to concatenate the lines after parsing. For an empty or
1150074f84c0SBram Moolenaar // comment line use an empty string.
1151074f84c0SBram Moolenaar // Insert NL characters at the start of each line, the string will
1152074f84c0SBram Moolenaar // be split again later in .get_lambda_tv().
1153074f84c0SBram Moolenaar if (*p == NUL || vim9_comment_start(p))
1154074f84c0SBram Moolenaar p = (char_u *)"";
1155074f84c0SBram Moolenaar plen = STRLEN(p);
1156074f84c0SBram Moolenaar pnl = vim_strnsave((char_u *)"\n", plen + 1);
1157074f84c0SBram Moolenaar if (pnl != NULL)
1158074f84c0SBram Moolenaar mch_memmove(pnl + 1, p, plen + 1);
1159ecb66450SBram Moolenaar ((char_u **)gap->ga_data)[gap->ga_len++] = pnl;
1160ecb66450SBram Moolenaar ((char_u **)freegap->ga_data)[freegap->ga_len++] = pnl;
1161074f84c0SBram Moolenaar }
1162ecb66450SBram Moolenaar if (ga_grow(gap, 1) == FAIL || ga_grow(freegap, 1) == FAIL)
1163074f84c0SBram Moolenaar goto erret;
1164074f84c0SBram Moolenaar if (cmdline != NULL)
1165074f84c0SBram Moolenaar // more is following after the "}", which was skipped
1166074f84c0SBram Moolenaar last = cmdline;
1167074f84c0SBram Moolenaar else
1168074f84c0SBram Moolenaar // nothing is following the "}"
1169074f84c0SBram Moolenaar last = (char_u *)"}";
1170074f84c0SBram Moolenaar plen = STRLEN(last);
1171074f84c0SBram Moolenaar pnl = vim_strnsave((char_u *)"\n", plen + 1);
1172074f84c0SBram Moolenaar if (pnl != NULL)
1173074f84c0SBram Moolenaar mch_memmove(pnl + 1, last, plen + 1);
1174ecb66450SBram Moolenaar ((char_u **)gap->ga_data)[gap->ga_len++] = pnl;
1175ecb66450SBram Moolenaar ((char_u **)freegap->ga_data)[freegap->ga_len++] = pnl;
1176074f84c0SBram Moolenaar }
1177074f84c0SBram Moolenaar
11787a6eaa06SBram Moolenaar if (cmdline != NULL)
11797a6eaa06SBram Moolenaar {
1180844fb64aSBram Moolenaar garray_T *tfgap = &evalarg->eval_tofree_ga;
1181844fb64aSBram Moolenaar
11827a6eaa06SBram Moolenaar // Something comes after the "}".
11837a6eaa06SBram Moolenaar *arg = eap.nextcmd;
118467da21a1SBram Moolenaar
118567da21a1SBram Moolenaar // "arg" points into cmdline, need to keep the line and free it later.
1186844fb64aSBram Moolenaar if (ga_grow(tfgap, 1) == OK)
1187844fb64aSBram Moolenaar {
1188844fb64aSBram Moolenaar ((char_u **)(tfgap->ga_data))[tfgap->ga_len++] = cmdline;
1189844fb64aSBram Moolenaar evalarg->eval_using_cmdline = TRUE;
1190844fb64aSBram Moolenaar }
11917a6eaa06SBram Moolenaar }
11927a6eaa06SBram Moolenaar else
11937a6eaa06SBram Moolenaar *arg = (char_u *)"";
11947a6eaa06SBram Moolenaar
1195074f84c0SBram Moolenaar if (!evaluate)
1196074f84c0SBram Moolenaar {
1197074f84c0SBram Moolenaar ret = OK;
1198074f84c0SBram Moolenaar goto erret;
1199074f84c0SBram Moolenaar }
1200074f84c0SBram Moolenaar
12017a6eaa06SBram Moolenaar name = get_lambda_name();
12027a6eaa06SBram Moolenaar ufunc = alloc_clear(offsetof(ufunc_T, uf_name) + STRLEN(name) + 1);
12037a6eaa06SBram Moolenaar if (ufunc == NULL)
12047a6eaa06SBram Moolenaar goto erret;
12057a6eaa06SBram Moolenaar set_ufunc_name(ufunc, name);
12067a6eaa06SBram Moolenaar if (hash_add(&func_hashtab, UF2HIKEY(ufunc)) == FAIL)
12077a6eaa06SBram Moolenaar goto erret;
12087a6eaa06SBram Moolenaar ufunc->uf_refcount = 1;
12097a6eaa06SBram Moolenaar ufunc->uf_args = *newargs;
12107a6eaa06SBram Moolenaar newargs->ga_data = NULL;
12117a6eaa06SBram Moolenaar ufunc->uf_def_args = *default_args;
12127a6eaa06SBram Moolenaar default_args->ga_data = NULL;
12137a6eaa06SBram Moolenaar ufunc->uf_func_type = &t_func_any;
12147a6eaa06SBram Moolenaar
12157a6eaa06SBram Moolenaar // error messages are for the first function line
12167a6eaa06SBram Moolenaar lnum_save = SOURCING_LNUM;
12177a6eaa06SBram Moolenaar SOURCING_LNUM = sourcing_lnum_top;
12187a6eaa06SBram Moolenaar
12197a6eaa06SBram Moolenaar // parse argument types
12207a6eaa06SBram Moolenaar if (parse_argument_types(ufunc, argtypes, varargs) == FAIL)
12217a6eaa06SBram Moolenaar {
12227a6eaa06SBram Moolenaar SOURCING_LNUM = lnum_save;
12237a6eaa06SBram Moolenaar goto erret;
12247a6eaa06SBram Moolenaar }
12257a6eaa06SBram Moolenaar
12267a6eaa06SBram Moolenaar // parse the return type, if any
12277a6eaa06SBram Moolenaar if (parse_return_type(ufunc, ret_type) == FAIL)
12287a6eaa06SBram Moolenaar goto erret;
12297a6eaa06SBram Moolenaar
12307a6eaa06SBram Moolenaar pt = ALLOC_CLEAR_ONE(partial_T);
12317a6eaa06SBram Moolenaar if (pt == NULL)
12327a6eaa06SBram Moolenaar goto erret;
12337a6eaa06SBram Moolenaar pt->pt_func = ufunc;
12347a6eaa06SBram Moolenaar pt->pt_refcount = 1;
12357a6eaa06SBram Moolenaar
12367a6eaa06SBram Moolenaar ufunc->uf_lines = newlines;
12377a6eaa06SBram Moolenaar newlines.ga_data = NULL;
12387a6eaa06SBram Moolenaar if (sandbox)
12397a6eaa06SBram Moolenaar ufunc->uf_flags |= FC_SANDBOX;
12407a6eaa06SBram Moolenaar if (!ASCII_ISUPPER(*ufunc->uf_name))
12417a6eaa06SBram Moolenaar ufunc->uf_flags |= FC_VIM9;
12427a6eaa06SBram Moolenaar ufunc->uf_script_ctx = current_sctx;
12437a6eaa06SBram Moolenaar ufunc->uf_script_ctx_version = current_sctx.sc_version;
12447a6eaa06SBram Moolenaar ufunc->uf_script_ctx.sc_lnum += sourcing_lnum_top;
12457a6eaa06SBram Moolenaar set_function_type(ufunc);
12467a6eaa06SBram Moolenaar
12472eb6fc3bSBram Moolenaar function_using_block_scopes(ufunc, evalarg->eval_cstack);
12482eb6fc3bSBram Moolenaar
12497a6eaa06SBram Moolenaar rettv->vval.v_partial = pt;
12507a6eaa06SBram Moolenaar rettv->v_type = VAR_PARTIAL;
125179efa2e3SBram Moolenaar ufunc = NULL;
12527a6eaa06SBram Moolenaar ret = OK;
12537a6eaa06SBram Moolenaar
12547a6eaa06SBram Moolenaar erret:
12557a6eaa06SBram Moolenaar if (lnum_save >= 0)
12567a6eaa06SBram Moolenaar SOURCING_LNUM = lnum_save;
12577a6eaa06SBram Moolenaar vim_free(line_to_free);
12587a6eaa06SBram Moolenaar ga_clear_strings(&newlines);
1259074f84c0SBram Moolenaar if (newargs != NULL)
12607a6eaa06SBram Moolenaar ga_clear_strings(newargs);
12617a6eaa06SBram Moolenaar ga_clear_strings(default_args);
126279efa2e3SBram Moolenaar if (ufunc != NULL)
126379efa2e3SBram Moolenaar {
126479efa2e3SBram Moolenaar func_clear(ufunc, TRUE);
126579efa2e3SBram Moolenaar func_free(ufunc, TRUE);
126679efa2e3SBram Moolenaar }
12677a6eaa06SBram Moolenaar return ret;
12687a6eaa06SBram Moolenaar }
12697a6eaa06SBram Moolenaar
12707a6eaa06SBram Moolenaar /*
12717a6eaa06SBram Moolenaar * Parse a lambda expression and get a Funcref from "*arg" into "rettv".
127265c44152SBram Moolenaar * "arg" points to the { in "{arg -> expr}" or the ( in "(arg) => expr"
1273b4d16cb1SBram Moolenaar * When "types_optional" is TRUE optionally take argument types.
1274a9b579f3SBram Moolenaar * Return OK or FAIL. Returns NOTDONE for dict or {expr}.
1275a9b579f3SBram Moolenaar */
1276a9b579f3SBram Moolenaar int
get_lambda_tv(char_u ** arg,typval_T * rettv,int types_optional,evalarg_T * evalarg)1277b4d16cb1SBram Moolenaar get_lambda_tv(
1278b4d16cb1SBram Moolenaar char_u **arg,
1279b4d16cb1SBram Moolenaar typval_T *rettv,
1280b4d16cb1SBram Moolenaar int types_optional,
1281b4d16cb1SBram Moolenaar evalarg_T *evalarg)
1282a9b579f3SBram Moolenaar {
1283e40fbc2cSBram Moolenaar int evaluate = evalarg != NULL
1284e40fbc2cSBram Moolenaar && (evalarg->eval_flags & EVAL_EVALUATE);
1285a9b579f3SBram Moolenaar garray_T newargs;
1286a9b579f3SBram Moolenaar garray_T newlines;
12871e96d9bfSBram Moolenaar garray_T *pnewargs;
1288b4d16cb1SBram Moolenaar garray_T argtypes;
12897a6eaa06SBram Moolenaar garray_T default_args;
1290a9b579f3SBram Moolenaar ufunc_T *fp = NULL;
1291445e71c5SBram Moolenaar partial_T *pt = NULL;
1292a9b579f3SBram Moolenaar int varargs;
12939e68c325SBram Moolenaar char_u *ret_type = NULL;
1294a9b579f3SBram Moolenaar int ret;
12958e2730a3SBram Moolenaar char_u *s;
12968e2730a3SBram Moolenaar char_u *start, *end;
12971e96d9bfSBram Moolenaar int *old_eval_lavars = eval_lavars_used;
12981e96d9bfSBram Moolenaar int eval_lavars = FALSE;
1299f898f7c6SBram Moolenaar char_u *tofree1 = NULL;
1300f898f7c6SBram Moolenaar char_u *tofree2 = NULL;
130165c44152SBram Moolenaar int equal_arrow = **arg == '(';
1302c754b4ccSBram Moolenaar int white_error = FALSE;
13030346b799SBram Moolenaar int called_emsg_start = called_emsg;
130465c44152SBram Moolenaar
130565c44152SBram Moolenaar if (equal_arrow && !in_vim9script())
130665c44152SBram Moolenaar return NOTDONE;
1307a9b579f3SBram Moolenaar
1308a9b579f3SBram Moolenaar ga_init(&newargs);
1309a9b579f3SBram Moolenaar ga_init(&newlines);
1310a9b579f3SBram Moolenaar
13119e68c325SBram Moolenaar // First, check if this is really a lambda expression. "->" or "=>" must
13129e68c325SBram Moolenaar // be found after the arguments.
1313cef1270dSBram Moolenaar s = *arg + 1;
131465c44152SBram Moolenaar ret = get_function_args(&s, equal_arrow ? ')' : '-', NULL,
1315057e84afSBram Moolenaar types_optional ? &argtypes : NULL, types_optional, evalarg,
131614ded11fSBram Moolenaar NULL, &default_args, TRUE, NULL, NULL);
1317c754b4ccSBram Moolenaar if (ret == FAIL || skip_arrow(s, equal_arrow, &ret_type, NULL) == NULL)
13186dd41b1dSBram Moolenaar {
13196dd41b1dSBram Moolenaar if (types_optional)
13206dd41b1dSBram Moolenaar ga_clear_strings(&argtypes);
13210346b799SBram Moolenaar return called_emsg == called_emsg_start ? NOTDONE : FAIL;
13226dd41b1dSBram Moolenaar }
1323a9b579f3SBram Moolenaar
13249e68c325SBram Moolenaar // Parse the arguments for real.
13251e96d9bfSBram Moolenaar if (evaluate)
13261e96d9bfSBram Moolenaar pnewargs = &newargs;
13271e96d9bfSBram Moolenaar else
13281e96d9bfSBram Moolenaar pnewargs = NULL;
1329cef1270dSBram Moolenaar *arg += 1;
133065c44152SBram Moolenaar ret = get_function_args(arg, equal_arrow ? ')' : '-', pnewargs,
1331057e84afSBram Moolenaar types_optional ? &argtypes : NULL, types_optional, evalarg,
13327a6eaa06SBram Moolenaar &varargs, &default_args,
13337a6eaa06SBram Moolenaar FALSE, NULL, NULL);
13349e68c325SBram Moolenaar if (ret == FAIL
1335c754b4ccSBram Moolenaar || (s = skip_arrow(*arg, equal_arrow, &ret_type,
1336e462f52dSBram Moolenaar equal_arrow || in_vim9script() ? &white_error : NULL)) == NULL)
13376dd41b1dSBram Moolenaar {
13386dd41b1dSBram Moolenaar if (types_optional)
13396dd41b1dSBram Moolenaar ga_clear_strings(&argtypes);
1340e5730bdcSBram Moolenaar ga_clear_strings(&newargs);
1341c754b4ccSBram Moolenaar return white_error ? FAIL : NOTDONE;
13426dd41b1dSBram Moolenaar }
1343c754b4ccSBram Moolenaar *arg = s;
1344a9b579f3SBram Moolenaar
1345f898f7c6SBram Moolenaar // Skipping over linebreaks may make "ret_type" invalid, make a copy.
1346f898f7c6SBram Moolenaar if (ret_type != NULL)
1347f898f7c6SBram Moolenaar {
1348f898f7c6SBram Moolenaar ret_type = vim_strsave(ret_type);
1349f898f7c6SBram Moolenaar tofree2 = ret_type;
1350f898f7c6SBram Moolenaar }
1351f898f7c6SBram Moolenaar
1352e38eab22SBram Moolenaar // Set up a flag for checking local variables and arguments.
13531e96d9bfSBram Moolenaar if (evaluate)
13541e96d9bfSBram Moolenaar eval_lavars_used = &eval_lavars;
13551e96d9bfSBram Moolenaar
135665c44152SBram Moolenaar *arg = skipwhite_and_linebreak(*arg, evalarg);
135765c44152SBram Moolenaar
13589e68c325SBram Moolenaar // Recognize "{" as the start of a function body.
13599e68c325SBram Moolenaar if (equal_arrow && **arg == '{')
136065c44152SBram Moolenaar {
1361fed9e830SBram Moolenaar if (evalarg == NULL)
1362fed9e830SBram Moolenaar // cannot happen?
1363fed9e830SBram Moolenaar goto theend;
13647a6eaa06SBram Moolenaar if (lambda_function_body(arg, rettv, evalarg, pnewargs,
13657a6eaa06SBram Moolenaar types_optional ? &argtypes : NULL, varargs,
13667a6eaa06SBram Moolenaar &default_args, ret_type) == FAIL)
13677a6eaa06SBram Moolenaar goto errret;
13687a6eaa06SBram Moolenaar goto theend;
13697a6eaa06SBram Moolenaar }
13707a6eaa06SBram Moolenaar if (default_args.ga_len > 0)
13717a6eaa06SBram Moolenaar {
13727a6eaa06SBram Moolenaar emsg(_(e_cannot_use_default_values_in_lambda));
137365c44152SBram Moolenaar goto errret;
137465c44152SBram Moolenaar }
137565c44152SBram Moolenaar
1376e38eab22SBram Moolenaar // Get the start and the end of the expression.
13778e2730a3SBram Moolenaar start = *arg;
13788e2730a3SBram Moolenaar ret = skip_expr_concatenate(arg, &start, &end, evalarg);
1379a9b579f3SBram Moolenaar if (ret == FAIL)
1380a9b579f3SBram Moolenaar goto errret;
1381e40fbc2cSBram Moolenaar if (evalarg != NULL)
1382e40fbc2cSBram Moolenaar {
1383e40fbc2cSBram Moolenaar // avoid that the expression gets freed when another line break follows
1384f898f7c6SBram Moolenaar tofree1 = evalarg->eval_tofree;
1385e40fbc2cSBram Moolenaar evalarg->eval_tofree = NULL;
1386e40fbc2cSBram Moolenaar }
1387e40fbc2cSBram Moolenaar
138865c44152SBram Moolenaar if (!equal_arrow)
138965c44152SBram Moolenaar {
13909215f012SBram Moolenaar *arg = skipwhite_and_linebreak(*arg, evalarg);
1391a9b579f3SBram Moolenaar if (**arg != '}')
1392ee619e5bSBram Moolenaar {
1393ee619e5bSBram Moolenaar semsg(_("E451: Expected }: %s"), *arg);
1394a9b579f3SBram Moolenaar goto errret;
1395ee619e5bSBram Moolenaar }
1396a9b579f3SBram Moolenaar ++*arg;
139765c44152SBram Moolenaar }
1398a9b579f3SBram Moolenaar
1399a9b579f3SBram Moolenaar if (evaluate)
1400a9b579f3SBram Moolenaar {
1401e40fbc2cSBram Moolenaar int len;
1402e40fbc2cSBram Moolenaar int flags = 0;
1403a9b579f3SBram Moolenaar char_u *p;
1404074f84c0SBram Moolenaar char_u *line_end;
140504b12697SBram Moolenaar char_u *name = get_lambda_name();
14061e96d9bfSBram Moolenaar
140747ed553fSBram Moolenaar fp = alloc_clear(offsetof(ufunc_T, uf_name) + STRLEN(name) + 1);
1408a9b579f3SBram Moolenaar if (fp == NULL)
1409a9b579f3SBram Moolenaar goto errret;
14100cb5bcf5SBram Moolenaar fp->uf_def_status = UF_NOT_COMPILED;
1411c799fe20SBram Moolenaar pt = ALLOC_CLEAR_ONE(partial_T);
1412437bafe4SBram Moolenaar if (pt == NULL)
1413437bafe4SBram Moolenaar goto errret;
1414a9b579f3SBram Moolenaar
1415a9b579f3SBram Moolenaar ga_init2(&newlines, (int)sizeof(char_u *), 1);
1416a9b579f3SBram Moolenaar if (ga_grow(&newlines, 1) == FAIL)
1417a9b579f3SBram Moolenaar goto errret;
1418a9b579f3SBram Moolenaar
1419074f84c0SBram Moolenaar // If there are line breaks, we need to split up the string.
1420074f84c0SBram Moolenaar line_end = vim_strchr(start, '\n');
14216868634aSBram Moolenaar if (line_end == NULL || line_end > end)
1422074f84c0SBram Moolenaar line_end = end;
1423074f84c0SBram Moolenaar
1424074f84c0SBram Moolenaar // Add "return " before the expression (or the first line).
1425074f84c0SBram Moolenaar len = 7 + (int)(line_end - start) + 1;
1426c799fe20SBram Moolenaar p = alloc(len);
1427a9b579f3SBram Moolenaar if (p == NULL)
1428a9b579f3SBram Moolenaar goto errret;
1429a9b579f3SBram Moolenaar ((char_u **)(newlines.ga_data))[newlines.ga_len++] = p;
1430a9b579f3SBram Moolenaar STRCPY(p, "return ");
1431074f84c0SBram Moolenaar vim_strncpy(p + 7, start, line_end - start);
1432074f84c0SBram Moolenaar
1433074f84c0SBram Moolenaar if (line_end != end)
1434074f84c0SBram Moolenaar {
1435074f84c0SBram Moolenaar // Add more lines, split by line breaks. Thus is used when a
1436074f84c0SBram Moolenaar // lambda with { cmds } is encountered.
1437074f84c0SBram Moolenaar while (*line_end == '\n')
1438074f84c0SBram Moolenaar {
1439074f84c0SBram Moolenaar if (ga_grow(&newlines, 1) == FAIL)
1440074f84c0SBram Moolenaar goto errret;
1441074f84c0SBram Moolenaar start = line_end + 1;
1442074f84c0SBram Moolenaar line_end = vim_strchr(start, '\n');
1443074f84c0SBram Moolenaar if (line_end == NULL)
1444074f84c0SBram Moolenaar line_end = end;
1445074f84c0SBram Moolenaar ((char_u **)(newlines.ga_data))[newlines.ga_len++] =
1446074f84c0SBram Moolenaar vim_strnsave(start, line_end - start);
1447074f84c0SBram Moolenaar }
1448074f84c0SBram Moolenaar }
1449074f84c0SBram Moolenaar
1450f10806b2SBram Moolenaar if (strstr((char *)p + 7, "a:") == NULL)
1451f10806b2SBram Moolenaar // No a: variables are used for sure.
1452f10806b2SBram Moolenaar flags |= FC_NOARGS;
1453a9b579f3SBram Moolenaar
1454a9b579f3SBram Moolenaar fp->uf_refcount = 1;
14551a47ae32SBram Moolenaar set_ufunc_name(fp, name);
1456a9b579f3SBram Moolenaar fp->uf_args = newargs;
145742ae78cfSBram Moolenaar ga_init(&fp->uf_def_args);
14589e68c325SBram Moolenaar if (types_optional)
14599e68c325SBram Moolenaar {
14602a38908bSBram Moolenaar if (parse_argument_types(fp, &argtypes,
14612a38908bSBram Moolenaar in_vim9script() && varargs) == FAIL)
1462b4d16cb1SBram Moolenaar goto errret;
14639e68c325SBram Moolenaar if (ret_type != NULL)
14649e68c325SBram Moolenaar {
14659e68c325SBram Moolenaar fp->uf_ret_type = parse_type(&ret_type,
14669e68c325SBram Moolenaar &fp->uf_type_list, TRUE);
14679e68c325SBram Moolenaar if (fp->uf_ret_type == NULL)
14689e68c325SBram Moolenaar goto errret;
14699e68c325SBram Moolenaar }
1470ca2f7e7aSBram Moolenaar else
1471a9931535SBram Moolenaar fp->uf_ret_type = &t_unknown;
14729e68c325SBram Moolenaar }
1473b4d16cb1SBram Moolenaar
1474a9b579f3SBram Moolenaar fp->uf_lines = newlines;
14751e96d9bfSBram Moolenaar if (current_funccal != NULL && eval_lavars)
14761e96d9bfSBram Moolenaar {
147710ce39a0SBram Moolenaar flags |= FC_CLOSURE;
147858016448SBram Moolenaar if (register_closure(fp) == FAIL)
14791e96d9bfSBram Moolenaar goto errret;
14801e96d9bfSBram Moolenaar }
1481a9b579f3SBram Moolenaar
1482a9b579f3SBram Moolenaar #ifdef FEAT_PROFILE
1483a9b579f3SBram Moolenaar if (prof_def_func())
1484a9b579f3SBram Moolenaar func_do_profile(fp);
1485a9b579f3SBram Moolenaar #endif
148693343725SBram Moolenaar if (sandbox)
148793343725SBram Moolenaar flags |= FC_SANDBOX;
1488767034c5SBram Moolenaar // In legacy script a lambda can be called with more args than
14892a38908bSBram Moolenaar // uf_args.ga_len. In Vim9 script "...name" has to be used.
14902a38908bSBram Moolenaar fp->uf_varargs = !in_vim9script() || varargs;
149110ce39a0SBram Moolenaar fp->uf_flags = flags;
1492a9b579f3SBram Moolenaar fp->uf_calls = 0;
1493f29c1c6aSBram Moolenaar fp->uf_script_ctx = current_sctx;
1494a755fdbeSBram Moolenaar fp->uf_script_ctx.sc_lnum += SOURCING_LNUM - newlines.ga_len + 1;
1495a9b579f3SBram Moolenaar
14962eb6fc3bSBram Moolenaar function_using_block_scopes(fp, evalarg->eval_cstack);
14972eb6fc3bSBram Moolenaar
1498437bafe4SBram Moolenaar pt->pt_func = fp;
1499437bafe4SBram Moolenaar pt->pt_refcount = 1;
1500437bafe4SBram Moolenaar rettv->vval.v_partial = pt;
1501437bafe4SBram Moolenaar rettv->v_type = VAR_PARTIAL;
1502057e84afSBram Moolenaar
1503057e84afSBram Moolenaar hash_add(&func_hashtab, UF2HIKEY(fp));
1504a9b579f3SBram Moolenaar }
1505a9b579f3SBram Moolenaar
15067a6eaa06SBram Moolenaar theend:
15071e96d9bfSBram Moolenaar eval_lavars_used = old_eval_lavars;
1508efaaaa68SBram Moolenaar if (evalarg != NULL && evalarg->eval_tofree == NULL)
1509f898f7c6SBram Moolenaar evalarg->eval_tofree = tofree1;
15108e2730a3SBram Moolenaar else
1511f898f7c6SBram Moolenaar vim_free(tofree1);
1512f898f7c6SBram Moolenaar vim_free(tofree2);
1513b4d16cb1SBram Moolenaar if (types_optional)
1514b4d16cb1SBram Moolenaar ga_clear_strings(&argtypes);
15152eb6fc3bSBram Moolenaar
1516a9b579f3SBram Moolenaar return OK;
1517a9b579f3SBram Moolenaar
1518a9b579f3SBram Moolenaar errret:
1519a9b579f3SBram Moolenaar ga_clear_strings(&newargs);
1520a9b579f3SBram Moolenaar ga_clear_strings(&newlines);
15217a6eaa06SBram Moolenaar ga_clear_strings(&default_args);
1522b4d16cb1SBram Moolenaar if (types_optional)
152315bbb8f4SBram Moolenaar {
1524b4d16cb1SBram Moolenaar ga_clear_strings(&argtypes);
152515bbb8f4SBram Moolenaar if (fp != NULL)
152615bbb8f4SBram Moolenaar vim_free(fp->uf_arg_types);
152715bbb8f4SBram Moolenaar }
1528a9b579f3SBram Moolenaar vim_free(fp);
1529445e71c5SBram Moolenaar vim_free(pt);
1530efaaaa68SBram Moolenaar if (evalarg != NULL && evalarg->eval_tofree == NULL)
1531f898f7c6SBram Moolenaar evalarg->eval_tofree = tofree1;
15328e2730a3SBram Moolenaar else
1533f898f7c6SBram Moolenaar vim_free(tofree1);
1534f898f7c6SBram Moolenaar vim_free(tofree2);
15351e96d9bfSBram Moolenaar eval_lavars_used = old_eval_lavars;
1536a9b579f3SBram Moolenaar return FAIL;
1537a9b579f3SBram Moolenaar }
1538a9b579f3SBram Moolenaar
1539a9b579f3SBram Moolenaar /*
1540a9b579f3SBram Moolenaar * Check if "name" is a variable of type VAR_FUNC. If so, return the function
1541a9b579f3SBram Moolenaar * name it contains, otherwise return "name".
1542a9b579f3SBram Moolenaar * If "partialp" is not NULL, and "name" is of type VAR_PARTIAL also set
1543a9b579f3SBram Moolenaar * "partialp".
154432b3f820SBram Moolenaar * If "type" is not NULL and a Vim9 script-local variable is found look up the
154532b3f820SBram Moolenaar * type of the variable.
1546a9b579f3SBram Moolenaar */
1547a9b579f3SBram Moolenaar char_u *
deref_func_name(char_u * name,int * lenp,partial_T ** partialp,type_T ** type,int no_autoload)154832b3f820SBram Moolenaar deref_func_name(
154932b3f820SBram Moolenaar char_u *name,
155032b3f820SBram Moolenaar int *lenp,
155132b3f820SBram Moolenaar partial_T **partialp,
155232b3f820SBram Moolenaar type_T **type,
155332b3f820SBram Moolenaar int no_autoload)
1554a9b579f3SBram Moolenaar {
1555a9b579f3SBram Moolenaar dictitem_T *v;
15565fe07d2eSBram Moolenaar typval_T *tv = NULL;
1557a9b579f3SBram Moolenaar int cc;
155832b3f820SBram Moolenaar char_u *s = NULL;
155932b3f820SBram Moolenaar hashtab_T *ht;
15605fe07d2eSBram Moolenaar int did_type = FALSE;
1561a9b579f3SBram Moolenaar
1562a9b579f3SBram Moolenaar if (partialp != NULL)
1563a9b579f3SBram Moolenaar *partialp = NULL;
1564a9b579f3SBram Moolenaar
1565a9b579f3SBram Moolenaar cc = name[*lenp];
1566a9b579f3SBram Moolenaar name[*lenp] = NUL;
15672067733bSBram Moolenaar
156832b3f820SBram Moolenaar v = find_var(name, &ht, no_autoload);
1569a9b579f3SBram Moolenaar name[*lenp] = cc;
157032b3f820SBram Moolenaar if (v != NULL)
157132b3f820SBram Moolenaar {
15725fe07d2eSBram Moolenaar tv = &v->di_tv;
15735fe07d2eSBram Moolenaar }
15745fe07d2eSBram Moolenaar else if (in_vim9script() || STRNCMP(name, "s:", 2) == 0)
1575a9b579f3SBram Moolenaar {
15765fe07d2eSBram Moolenaar imported_T *import;
15775fe07d2eSBram Moolenaar char_u *p = name;
15785fe07d2eSBram Moolenaar int len = *lenp;
15795fe07d2eSBram Moolenaar
15805fe07d2eSBram Moolenaar if (STRNCMP(name, "s:", 2) == 0)
15815fe07d2eSBram Moolenaar {
15825fe07d2eSBram Moolenaar p = name + 2;
15835fe07d2eSBram Moolenaar len -= 2;
15845fe07d2eSBram Moolenaar }
15855fe07d2eSBram Moolenaar import = find_imported(p, len, NULL);
15865fe07d2eSBram Moolenaar
15875fe07d2eSBram Moolenaar // imported variable from another script
15885fe07d2eSBram Moolenaar if (import != NULL)
15895fe07d2eSBram Moolenaar {
15905fe07d2eSBram Moolenaar if (import->imp_funcname != NULL)
15915fe07d2eSBram Moolenaar {
15925fe07d2eSBram Moolenaar s = import->imp_funcname;
15935fe07d2eSBram Moolenaar *lenp = (int)STRLEN(s);
15945fe07d2eSBram Moolenaar return s;
15955fe07d2eSBram Moolenaar }
15965fe07d2eSBram Moolenaar // TODO: what if (import->imp_flags & IMP_FLAGS_STAR)
15975fe07d2eSBram Moolenaar {
15985fe07d2eSBram Moolenaar scriptitem_T *si = SCRIPT_ITEM(import->imp_sid);
15995fe07d2eSBram Moolenaar svar_T *sv = ((svar_T *)si->sn_var_vals.ga_data)
16005fe07d2eSBram Moolenaar + import->imp_var_vals_idx;
16015fe07d2eSBram Moolenaar tv = sv->sv_tv;
16025fe07d2eSBram Moolenaar if (type != NULL)
16035fe07d2eSBram Moolenaar *type = sv->sv_type;
16045fe07d2eSBram Moolenaar did_type = TRUE;
16055fe07d2eSBram Moolenaar }
16065fe07d2eSBram Moolenaar }
16075fe07d2eSBram Moolenaar }
16085fe07d2eSBram Moolenaar
16095fe07d2eSBram Moolenaar if (tv != NULL)
16105fe07d2eSBram Moolenaar {
16115fe07d2eSBram Moolenaar if (tv->v_type == VAR_FUNC)
16125fe07d2eSBram Moolenaar {
16135fe07d2eSBram Moolenaar if (tv->vval.v_string == NULL)
1614a9b579f3SBram Moolenaar {
1615a9b579f3SBram Moolenaar *lenp = 0;
1616e38eab22SBram Moolenaar return (char_u *)""; // just in case
1617a9b579f3SBram Moolenaar }
16185fe07d2eSBram Moolenaar s = tv->vval.v_string;
1619437bafe4SBram Moolenaar *lenp = (int)STRLEN(s);
1620a9b579f3SBram Moolenaar }
1621a9b579f3SBram Moolenaar
16225fe07d2eSBram Moolenaar if (tv->v_type == VAR_PARTIAL)
1623a9b579f3SBram Moolenaar {
16245fe07d2eSBram Moolenaar partial_T *pt = tv->vval.v_partial;
1625a9b579f3SBram Moolenaar
1626a9b579f3SBram Moolenaar if (pt == NULL)
1627a9b579f3SBram Moolenaar {
1628a9b579f3SBram Moolenaar *lenp = 0;
1629e38eab22SBram Moolenaar return (char_u *)""; // just in case
1630a9b579f3SBram Moolenaar }
1631a9b579f3SBram Moolenaar if (partialp != NULL)
1632a9b579f3SBram Moolenaar *partialp = pt;
1633437bafe4SBram Moolenaar s = partial_name(pt);
1634437bafe4SBram Moolenaar *lenp = (int)STRLEN(s);
163532b3f820SBram Moolenaar }
163632b3f820SBram Moolenaar
163732b3f820SBram Moolenaar if (s != NULL)
163832b3f820SBram Moolenaar {
16395fe07d2eSBram Moolenaar if (!did_type && type != NULL && ht == get_script_local_ht())
164032b3f820SBram Moolenaar {
16415fe07d2eSBram Moolenaar svar_T *sv = find_typval_in_script(tv);
164232b3f820SBram Moolenaar
164332b3f820SBram Moolenaar if (sv != NULL)
164432b3f820SBram Moolenaar *type = sv->sv_type;
164532b3f820SBram Moolenaar }
1646437bafe4SBram Moolenaar return s;
1647a9b579f3SBram Moolenaar }
164832b3f820SBram Moolenaar }
1649a9b579f3SBram Moolenaar
1650a9b579f3SBram Moolenaar return name;
1651a9b579f3SBram Moolenaar }
1652a9b579f3SBram Moolenaar
1653a9b579f3SBram Moolenaar /*
1654a9b579f3SBram Moolenaar * Give an error message with a function name. Handle <SNR> things.
1655a9b579f3SBram Moolenaar * "ermsg" is to be passed without translation, use N_() instead of _().
1656a9b579f3SBram Moolenaar */
16574c054e9fSBram Moolenaar void
emsg_funcname(char * ermsg,char_u * name)1658a9b579f3SBram Moolenaar emsg_funcname(char *ermsg, char_u *name)
1659a9b579f3SBram Moolenaar {
1660a9b579f3SBram Moolenaar char_u *p;
1661a9b579f3SBram Moolenaar
1662a9b579f3SBram Moolenaar if (*name == K_SPECIAL)
1663a9b579f3SBram Moolenaar p = concat_str((char_u *)"<SNR>", name + 3);
1664a9b579f3SBram Moolenaar else
1665a9b579f3SBram Moolenaar p = name;
1666f9e3e09fSBram Moolenaar semsg(_(ermsg), p);
1667a9b579f3SBram Moolenaar if (p != name)
1668a9b579f3SBram Moolenaar vim_free(p);
1669a9b579f3SBram Moolenaar }
1670a9b579f3SBram Moolenaar
1671a9b579f3SBram Moolenaar /*
1672a9b579f3SBram Moolenaar * Allocate a variable for the result of a function.
1673a9b579f3SBram Moolenaar * Return OK or FAIL.
1674a9b579f3SBram Moolenaar */
1675a9b579f3SBram Moolenaar int
get_func_tv(char_u * name,int len,typval_T * rettv,char_u ** arg,evalarg_T * evalarg,funcexe_T * funcexe)1676a9b579f3SBram Moolenaar get_func_tv(
16776ed88198SBram Moolenaar char_u *name, // name of the function
16786ed88198SBram Moolenaar int len, // length of "name" or -1 to use strlen()
1679a9b579f3SBram Moolenaar typval_T *rettv,
16806ed88198SBram Moolenaar char_u **arg, // argument, pointing to the '('
1681e6b5324eSBram Moolenaar evalarg_T *evalarg, // for line continuation
1682c6538bccSBram Moolenaar funcexe_T *funcexe) // various values
1683a9b579f3SBram Moolenaar {
1684a9b579f3SBram Moolenaar char_u *argp;
1685a9b579f3SBram Moolenaar int ret = OK;
1686e38eab22SBram Moolenaar typval_T argvars[MAX_FUNC_ARGS + 1]; // vars for arguments
1687e38eab22SBram Moolenaar int argcount = 0; // number of arguments found
16887cb6fc29SBram Moolenaar int vim9script = in_vim9script();
1689a9b579f3SBram Moolenaar
1690a9b579f3SBram Moolenaar /*
1691a9b579f3SBram Moolenaar * Get the arguments.
1692a9b579f3SBram Moolenaar */
1693a9b579f3SBram Moolenaar argp = *arg;
1694c6538bccSBram Moolenaar while (argcount < MAX_FUNC_ARGS - (funcexe->partial == NULL ? 0
1695c6538bccSBram Moolenaar : funcexe->partial->pt_argc))
1696a9b579f3SBram Moolenaar {
1697e6b5324eSBram Moolenaar // skip the '(' or ',' and possibly line breaks
1698e6b5324eSBram Moolenaar argp = skipwhite_and_linebreak(argp + 1, evalarg);
1699e6b5324eSBram Moolenaar
1700a9b579f3SBram Moolenaar if (*argp == ')' || *argp == ',' || *argp == NUL)
1701a9b579f3SBram Moolenaar break;
1702e6b5324eSBram Moolenaar if (eval1(&argp, &argvars[argcount], evalarg) == FAIL)
1703a9b579f3SBram Moolenaar {
1704a9b579f3SBram Moolenaar ret = FAIL;
1705a9b579f3SBram Moolenaar break;
1706a9b579f3SBram Moolenaar }
1707a9b579f3SBram Moolenaar ++argcount;
17089d489566SBram Moolenaar // The comma should come right after the argument, but this wasn't
17099d489566SBram Moolenaar // checked previously, thus only enforce it in Vim9 script.
17107cb6fc29SBram Moolenaar if (vim9script)
17117cb6fc29SBram Moolenaar {
17127cb6fc29SBram Moolenaar if (*argp != ',' && *skipwhite(argp) == ',')
17137cb6fc29SBram Moolenaar {
1714ba98fb54SBram Moolenaar semsg(_(e_no_white_space_allowed_before_str_str), ",", argp);
17157cb6fc29SBram Moolenaar ret = FAIL;
17167cb6fc29SBram Moolenaar break;
17177cb6fc29SBram Moolenaar }
17187cb6fc29SBram Moolenaar }
17197cb6fc29SBram Moolenaar else
17209d489566SBram Moolenaar argp = skipwhite(argp);
1721a9b579f3SBram Moolenaar if (*argp != ',')
1722a9b579f3SBram Moolenaar break;
17237cb6fc29SBram Moolenaar if (vim9script && !IS_WHITE_OR_NUL(argp[1]))
17247cb6fc29SBram Moolenaar {
1725c3fc75dbSBram Moolenaar semsg(_(e_white_space_required_after_str_str), ",", argp);
17267cb6fc29SBram Moolenaar ret = FAIL;
17277cb6fc29SBram Moolenaar break;
17287cb6fc29SBram Moolenaar }
1729a9b579f3SBram Moolenaar }
1730e6b5324eSBram Moolenaar argp = skipwhite_and_linebreak(argp, evalarg);
1731a9b579f3SBram Moolenaar if (*argp == ')')
1732a9b579f3SBram Moolenaar ++argp;
1733a9b579f3SBram Moolenaar else
1734a9b579f3SBram Moolenaar ret = FAIL;
1735a9b579f3SBram Moolenaar
1736a9b579f3SBram Moolenaar if (ret == OK)
1737a9b579f3SBram Moolenaar {
1738a9b579f3SBram Moolenaar int i = 0;
1739327d3ee4SBram Moolenaar int did_emsg_before = did_emsg;
1740a9b579f3SBram Moolenaar
1741a9b579f3SBram Moolenaar if (get_vim_var_nr(VV_TESTING))
1742a9b579f3SBram Moolenaar {
1743e38eab22SBram Moolenaar // Prepare for calling test_garbagecollect_now(), need to know
1744e38eab22SBram Moolenaar // what variables are used on the call stack.
1745a9b579f3SBram Moolenaar if (funcargs.ga_itemsize == 0)
1746a9b579f3SBram Moolenaar ga_init2(&funcargs, (int)sizeof(typval_T *), 50);
1747a9b579f3SBram Moolenaar for (i = 0; i < argcount; ++i)
1748a9b579f3SBram Moolenaar if (ga_grow(&funcargs, 1) == OK)
1749a9b579f3SBram Moolenaar ((typval_T **)funcargs.ga_data)[funcargs.ga_len++] =
1750a9b579f3SBram Moolenaar &argvars[i];
1751a9b579f3SBram Moolenaar }
1752a9b579f3SBram Moolenaar
1753c6538bccSBram Moolenaar ret = call_func(name, len, rettv, argcount, argvars, funcexe);
1754327d3ee4SBram Moolenaar if (in_vim9script() && did_emsg > did_emsg_before)
17556e850a69SBram Moolenaar {
1756327d3ee4SBram Moolenaar // An error in a builtin function does not return FAIL, but we do
1757327d3ee4SBram Moolenaar // want to abort further processing if an error was given.
1758327d3ee4SBram Moolenaar ret = FAIL;
17596e850a69SBram Moolenaar clear_tv(rettv);
17606e850a69SBram Moolenaar }
1761a9b579f3SBram Moolenaar
1762a9b579f3SBram Moolenaar funcargs.ga_len -= i;
1763a9b579f3SBram Moolenaar }
1764a9b579f3SBram Moolenaar else if (!aborting())
1765a9b579f3SBram Moolenaar {
1766a9b579f3SBram Moolenaar if (argcount == MAX_FUNC_ARGS)
1767a9b579f3SBram Moolenaar emsg_funcname(N_("E740: Too many arguments for function %s"), name);
1768a9b579f3SBram Moolenaar else
1769a9b579f3SBram Moolenaar emsg_funcname(N_("E116: Invalid arguments for function %s"), name);
1770a9b579f3SBram Moolenaar }
1771a9b579f3SBram Moolenaar
1772a9b579f3SBram Moolenaar while (--argcount >= 0)
1773a9b579f3SBram Moolenaar clear_tv(&argvars[argcount]);
1774a9b579f3SBram Moolenaar
17758294d499SBram Moolenaar if (in_vim9script())
17768294d499SBram Moolenaar *arg = argp;
17778294d499SBram Moolenaar else
1778a9b579f3SBram Moolenaar *arg = skipwhite(argp);
1779a9b579f3SBram Moolenaar return ret;
1780a9b579f3SBram Moolenaar }
1781a9b579f3SBram Moolenaar
1782a9b579f3SBram Moolenaar /*
1783a9b579f3SBram Moolenaar * Return TRUE if "p" starts with "<SID>" or "s:".
1784a9b579f3SBram Moolenaar * Only works if eval_fname_script() returned non-zero for "p"!
1785a9b579f3SBram Moolenaar */
1786a9b579f3SBram Moolenaar static int
eval_fname_sid(char_u * p)1787a9b579f3SBram Moolenaar eval_fname_sid(char_u *p)
1788a9b579f3SBram Moolenaar {
1789a9b579f3SBram Moolenaar return (*p == 's' || TOUPPER_ASC(p[2]) == 'I');
1790a9b579f3SBram Moolenaar }
1791a9b579f3SBram Moolenaar
1792a9b579f3SBram Moolenaar /*
1793a9b579f3SBram Moolenaar * In a script change <SID>name() and s:name() to K_SNR 123_name().
1794a9b579f3SBram Moolenaar * Change <SNR>123_name() to K_SNR 123_name().
1795a9b579f3SBram Moolenaar * Use "fname_buf[FLEN_FIXED + 1]" when it fits, otherwise allocate memory
1796a9b579f3SBram Moolenaar * (slow).
1797a9b579f3SBram Moolenaar */
17985cab73f8SBram Moolenaar char_u *
fname_trans_sid(char_u * name,char_u * fname_buf,char_u ** tofree,int * error)1799a9b579f3SBram Moolenaar fname_trans_sid(char_u *name, char_u *fname_buf, char_u **tofree, int *error)
1800a9b579f3SBram Moolenaar {
1801a9b579f3SBram Moolenaar int llen;
1802a9b579f3SBram Moolenaar char_u *fname;
1803a9b579f3SBram Moolenaar int i;
1804a9b579f3SBram Moolenaar
1805a9b579f3SBram Moolenaar llen = eval_fname_script(name);
1806a9b579f3SBram Moolenaar if (llen > 0)
1807a9b579f3SBram Moolenaar {
1808a9b579f3SBram Moolenaar fname_buf[0] = K_SPECIAL;
1809a9b579f3SBram Moolenaar fname_buf[1] = KS_EXTRA;
1810a9b579f3SBram Moolenaar fname_buf[2] = (int)KE_SNR;
1811a9b579f3SBram Moolenaar i = 3;
1812e38eab22SBram Moolenaar if (eval_fname_sid(name)) // "<SID>" or "s:"
1813a9b579f3SBram Moolenaar {
1814f29c1c6aSBram Moolenaar if (current_sctx.sc_sid <= 0)
1815ef140544SBram Moolenaar *error = FCERR_SCRIPT;
1816a9b579f3SBram Moolenaar else
1817a9b579f3SBram Moolenaar {
1818ad3ec76bSBram Moolenaar sprintf((char *)fname_buf + 3, "%ld_",
1819ad3ec76bSBram Moolenaar (long)current_sctx.sc_sid);
1820a9b579f3SBram Moolenaar i = (int)STRLEN(fname_buf);
1821a9b579f3SBram Moolenaar }
1822a9b579f3SBram Moolenaar }
1823a9b579f3SBram Moolenaar if (i + STRLEN(name + llen) < FLEN_FIXED)
1824a9b579f3SBram Moolenaar {
1825a9b579f3SBram Moolenaar STRCPY(fname_buf + i, name + llen);
1826a9b579f3SBram Moolenaar fname = fname_buf;
1827a9b579f3SBram Moolenaar }
1828a9b579f3SBram Moolenaar else
1829a9b579f3SBram Moolenaar {
1830964b3746SBram Moolenaar fname = alloc(i + STRLEN(name + llen) + 1);
1831a9b579f3SBram Moolenaar if (fname == NULL)
1832ef140544SBram Moolenaar *error = FCERR_OTHER;
1833a9b579f3SBram Moolenaar else
1834a9b579f3SBram Moolenaar {
1835a9b579f3SBram Moolenaar *tofree = fname;
1836a9b579f3SBram Moolenaar mch_memmove(fname, fname_buf, (size_t)i);
1837a9b579f3SBram Moolenaar STRCPY(fname + i, name + llen);
1838a9b579f3SBram Moolenaar }
1839a9b579f3SBram Moolenaar }
1840a9b579f3SBram Moolenaar }
1841a9b579f3SBram Moolenaar else
1842a9b579f3SBram Moolenaar fname = name;
1843a9b579f3SBram Moolenaar return fname;
1844a9b579f3SBram Moolenaar }
1845a9b579f3SBram Moolenaar
1846a9b579f3SBram Moolenaar /*
18478a7d6542SBram Moolenaar * Find a function "name" in script "sid".
18488a7d6542SBram Moolenaar */
18498a7d6542SBram Moolenaar static ufunc_T *
find_func_with_sid(char_u * name,int sid)18508a7d6542SBram Moolenaar find_func_with_sid(char_u *name, int sid)
18518a7d6542SBram Moolenaar {
18528a7d6542SBram Moolenaar hashitem_T *hi;
18538a7d6542SBram Moolenaar char_u buffer[200];
18548a7d6542SBram Moolenaar
18558a7d6542SBram Moolenaar buffer[0] = K_SPECIAL;
18568a7d6542SBram Moolenaar buffer[1] = KS_EXTRA;
18578a7d6542SBram Moolenaar buffer[2] = (int)KE_SNR;
18588a7d6542SBram Moolenaar vim_snprintf((char *)buffer + 3, sizeof(buffer) - 3, "%ld_%s",
18598a7d6542SBram Moolenaar (long)sid, name);
18608a7d6542SBram Moolenaar hi = hash_find(&func_hashtab, buffer);
18618a7d6542SBram Moolenaar if (!HASHITEM_EMPTY(hi))
18628a7d6542SBram Moolenaar return HI2UF(hi);
18638a7d6542SBram Moolenaar
18648a7d6542SBram Moolenaar return NULL;
18658a7d6542SBram Moolenaar }
18668a7d6542SBram Moolenaar
18678a7d6542SBram Moolenaar /*
1868a9b579f3SBram Moolenaar * Find a function by name, return pointer to it in ufuncs.
18694c17ad94SBram Moolenaar * When "is_global" is true don't find script-local or imported functions.
1870a9b579f3SBram Moolenaar * Return NULL for unknown function.
1871a9b579f3SBram Moolenaar */
1872ce658356SBram Moolenaar ufunc_T *
find_func_even_dead(char_u * name,int is_global,cctx_T * cctx)18734c17ad94SBram Moolenaar find_func_even_dead(char_u *name, int is_global, cctx_T *cctx)
1874a9b579f3SBram Moolenaar {
1875a9b579f3SBram Moolenaar hashitem_T *hi;
18768a7d6542SBram Moolenaar ufunc_T *func;
18778a7d6542SBram Moolenaar imported_T *imported;
18788a7d6542SBram Moolenaar
18799721fb4eSBram Moolenaar if (!is_global)
18809721fb4eSBram Moolenaar {
18819721fb4eSBram Moolenaar char_u *after_script = NULL;
1882efa94447SBram Moolenaar long sid = 0;
188395006e3dSBram Moolenaar int find_script_local = in_vim9script()
188495006e3dSBram Moolenaar && eval_isnamec1(*name) && name[1] != ':';
18859721fb4eSBram Moolenaar
188695006e3dSBram Moolenaar if (find_script_local)
18878a7d6542SBram Moolenaar {
18888a7d6542SBram Moolenaar // Find script-local function before global one.
18898a7d6542SBram Moolenaar func = find_func_with_sid(name, current_sctx.sc_sid);
18908a7d6542SBram Moolenaar if (func != NULL)
18918a7d6542SBram Moolenaar return func;
18929721fb4eSBram Moolenaar }
18938a7d6542SBram Moolenaar
1894efa94447SBram Moolenaar if (name[0] == K_SPECIAL
18959721fb4eSBram Moolenaar && name[1] == KS_EXTRA
18969721fb4eSBram Moolenaar && name[2] == KE_SNR)
18979721fb4eSBram Moolenaar {
18989721fb4eSBram Moolenaar // Caller changes s: to <SNR>99_name.
18999721fb4eSBram Moolenaar
19009721fb4eSBram Moolenaar after_script = name + 3;
19019721fb4eSBram Moolenaar sid = getdigits(&after_script);
1902efa94447SBram Moolenaar if (*after_script == '_')
19039721fb4eSBram Moolenaar ++after_script;
19049721fb4eSBram Moolenaar else
19059721fb4eSBram Moolenaar after_script = NULL;
19069721fb4eSBram Moolenaar }
190795006e3dSBram Moolenaar if (find_script_local || after_script != NULL)
19089721fb4eSBram Moolenaar {
19099721fb4eSBram Moolenaar // Find imported function before global one.
1910efa94447SBram Moolenaar if (after_script != NULL && sid != current_sctx.sc_sid)
1911efa94447SBram Moolenaar imported = find_imported_in_script(after_script, 0, sid);
1912efa94447SBram Moolenaar else
1913efa94447SBram Moolenaar imported = find_imported(after_script == NULL
1914efa94447SBram Moolenaar ? name : after_script, 0, cctx);
19158a7d6542SBram Moolenaar if (imported != NULL && imported->imp_funcname != NULL)
19168a7d6542SBram Moolenaar {
19178a7d6542SBram Moolenaar hi = hash_find(&func_hashtab, imported->imp_funcname);
19188a7d6542SBram Moolenaar if (!HASHITEM_EMPTY(hi))
19198a7d6542SBram Moolenaar return HI2UF(hi);
19208a7d6542SBram Moolenaar }
19218a7d6542SBram Moolenaar }
19229721fb4eSBram Moolenaar }
1923a9b579f3SBram Moolenaar
1924a26b9700SBram Moolenaar hi = hash_find(&func_hashtab,
1925a26b9700SBram Moolenaar STRNCMP(name, "g:", 2) == 0 ? name + 2 : name);
1926a9b579f3SBram Moolenaar if (!HASHITEM_EMPTY(hi))
1927a9b579f3SBram Moolenaar return HI2UF(hi);
19288a7d6542SBram Moolenaar
19298a7d6542SBram Moolenaar return NULL;
19308a7d6542SBram Moolenaar }
19318a7d6542SBram Moolenaar
19328a7d6542SBram Moolenaar /*
19338a7d6542SBram Moolenaar * Find a function by name, return pointer to it in ufuncs.
19348a7d6542SBram Moolenaar * "cctx" is passed in a :def function to find imported functions.
19358a7d6542SBram Moolenaar * Return NULL for unknown or dead function.
19368a7d6542SBram Moolenaar */
19378a7d6542SBram Moolenaar ufunc_T *
find_func(char_u * name,int is_global,cctx_T * cctx)19384c17ad94SBram Moolenaar find_func(char_u *name, int is_global, cctx_T *cctx)
19398a7d6542SBram Moolenaar {
19404c17ad94SBram Moolenaar ufunc_T *fp = find_func_even_dead(name, is_global, cctx);
19418a7d6542SBram Moolenaar
19428a7d6542SBram Moolenaar if (fp != NULL && (fp->uf_flags & FC_DEAD) == 0)
19438a7d6542SBram Moolenaar return fp;
1944a9b579f3SBram Moolenaar return NULL;
1945a9b579f3SBram Moolenaar }
1946a9b579f3SBram Moolenaar
1947a9b579f3SBram Moolenaar /*
19480f769815SBram Moolenaar * Return TRUE if "ufunc" is a global function.
19490f769815SBram Moolenaar */
19500f769815SBram Moolenaar int
func_is_global(ufunc_T * ufunc)19510f769815SBram Moolenaar func_is_global(ufunc_T *ufunc)
19520f769815SBram Moolenaar {
19530f769815SBram Moolenaar return ufunc->uf_name[0] != K_SPECIAL;
19540f769815SBram Moolenaar }
19550f769815SBram Moolenaar
19560f769815SBram Moolenaar /*
1957a9b579f3SBram Moolenaar * Copy the function name of "fp" to buffer "buf".
1958a9b579f3SBram Moolenaar * "buf" must be able to hold the function name plus three bytes.
1959a9b579f3SBram Moolenaar * Takes care of script-local function names.
1960a9b579f3SBram Moolenaar */
1961a9b579f3SBram Moolenaar static void
cat_func_name(char_u * buf,ufunc_T * fp)1962a9b579f3SBram Moolenaar cat_func_name(char_u *buf, ufunc_T *fp)
1963a9b579f3SBram Moolenaar {
19640f769815SBram Moolenaar if (!func_is_global(fp))
1965a9b579f3SBram Moolenaar {
1966a9b579f3SBram Moolenaar STRCPY(buf, "<SNR>");
1967a9b579f3SBram Moolenaar STRCAT(buf, fp->uf_name + 3);
1968a9b579f3SBram Moolenaar }
1969a9b579f3SBram Moolenaar else
1970a9b579f3SBram Moolenaar STRCPY(buf, fp->uf_name);
1971a9b579f3SBram Moolenaar }
1972a9b579f3SBram Moolenaar
1973a9b579f3SBram Moolenaar /*
1974a9b579f3SBram Moolenaar * Add a number variable "name" to dict "dp" with value "nr".
1975a9b579f3SBram Moolenaar */
1976a9b579f3SBram Moolenaar static void
add_nr_var(dict_T * dp,dictitem_T * v,char * name,varnumber_T nr)1977a9b579f3SBram Moolenaar add_nr_var(
1978a9b579f3SBram Moolenaar dict_T *dp,
1979a9b579f3SBram Moolenaar dictitem_T *v,
1980a9b579f3SBram Moolenaar char *name,
1981a9b579f3SBram Moolenaar varnumber_T nr)
1982a9b579f3SBram Moolenaar {
1983a9b579f3SBram Moolenaar STRCPY(v->di_key, name);
1984a9b579f3SBram Moolenaar v->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX;
1985a9b579f3SBram Moolenaar hash_add(&dp->dv_hashtab, DI2HIKEY(v));
1986a9b579f3SBram Moolenaar v->di_tv.v_type = VAR_NUMBER;
1987a9b579f3SBram Moolenaar v->di_tv.v_lock = VAR_FIXED;
1988a9b579f3SBram Moolenaar v->di_tv.vval.v_number = nr;
1989a9b579f3SBram Moolenaar }
1990a9b579f3SBram Moolenaar
1991a9b579f3SBram Moolenaar /*
1992209b8e3eSBram Moolenaar * Free "fc".
1993a9b579f3SBram Moolenaar */
1994a9b579f3SBram Moolenaar static void
free_funccal(funccall_T * fc)1995209b8e3eSBram Moolenaar free_funccal(funccall_T *fc)
1996a9b579f3SBram Moolenaar {
19971e96d9bfSBram Moolenaar int i;
19981e96d9bfSBram Moolenaar
19991e96d9bfSBram Moolenaar for (i = 0; i < fc->fc_funcs.ga_len; ++i)
20001e96d9bfSBram Moolenaar {
20011e96d9bfSBram Moolenaar ufunc_T *fp = ((ufunc_T **)(fc->fc_funcs.ga_data))[i];
20021e96d9bfSBram Moolenaar
2003209b8e3eSBram Moolenaar // When garbage collecting a funccall_T may be freed before the
2004209b8e3eSBram Moolenaar // function that references it, clear its uf_scoped field.
2005209b8e3eSBram Moolenaar // The function may have been redefined and point to another
2006209b8e3eSBram Moolenaar // funccall_T, don't clear it then.
2007bc7ce675SBram Moolenaar if (fp != NULL && fp->uf_scoped == fc)
20081e96d9bfSBram Moolenaar fp->uf_scoped = NULL;
200958016448SBram Moolenaar }
201058016448SBram Moolenaar ga_clear(&fc->fc_funcs);
2011a9b579f3SBram Moolenaar
2012209b8e3eSBram Moolenaar func_ptr_unref(fc->func);
2013209b8e3eSBram Moolenaar vim_free(fc);
2014209b8e3eSBram Moolenaar }
2015a9b579f3SBram Moolenaar
2016209b8e3eSBram Moolenaar /*
2017209b8e3eSBram Moolenaar * Free "fc" and what it contains.
2018209b8e3eSBram Moolenaar * Can be called only when "fc" is kept beyond the period of it called,
2019209b8e3eSBram Moolenaar * i.e. after cleanup_function_call(fc).
2020209b8e3eSBram Moolenaar */
2021209b8e3eSBram Moolenaar static void
free_funccal_contents(funccall_T * fc)2022209b8e3eSBram Moolenaar free_funccal_contents(funccall_T *fc)
2023209b8e3eSBram Moolenaar {
2024209b8e3eSBram Moolenaar listitem_T *li;
2025209b8e3eSBram Moolenaar
2026209b8e3eSBram Moolenaar // Free all l: variables.
2027a9b579f3SBram Moolenaar vars_clear(&fc->l_vars.dv_hashtab);
2028a9b579f3SBram Moolenaar
2029209b8e3eSBram Moolenaar // Free all a: variables.
2030209b8e3eSBram Moolenaar vars_clear(&fc->l_avars.dv_hashtab);
2031209b8e3eSBram Moolenaar
2032209b8e3eSBram Moolenaar // Free the a:000 variables.
2033aeea7215SBram Moolenaar FOR_ALL_LIST_ITEMS(&fc->l_varlist, li)
2034a9b579f3SBram Moolenaar clear_tv(&li->li_tv);
2035a9b579f3SBram Moolenaar
2036209b8e3eSBram Moolenaar free_funccal(fc);
2037a9b579f3SBram Moolenaar }
2038a9b579f3SBram Moolenaar
2039a9b579f3SBram Moolenaar /*
20406914c64eSBram Moolenaar * Handle the last part of returning from a function: free the local hashtable.
20416914c64eSBram Moolenaar * Unless it is still in use by a closure.
20426914c64eSBram Moolenaar */
20436914c64eSBram Moolenaar static void
cleanup_function_call(funccall_T * fc)20446914c64eSBram Moolenaar cleanup_function_call(funccall_T *fc)
20456914c64eSBram Moolenaar {
2046209b8e3eSBram Moolenaar int may_free_fc = fc->fc_refcount <= 0;
2047209b8e3eSBram Moolenaar int free_fc = TRUE;
2048209b8e3eSBram Moolenaar
20496914c64eSBram Moolenaar current_funccal = fc->caller;
20506914c64eSBram Moolenaar
2051209b8e3eSBram Moolenaar // Free all l: variables if not referred.
2052209b8e3eSBram Moolenaar if (may_free_fc && fc->l_vars.dv_refcount == DO_NOT_FREE_CNT)
2053209b8e3eSBram Moolenaar vars_clear(&fc->l_vars.dv_hashtab);
2054209b8e3eSBram Moolenaar else
2055209b8e3eSBram Moolenaar free_fc = FALSE;
2056209b8e3eSBram Moolenaar
2057209b8e3eSBram Moolenaar // If the a:000 list and the l: and a: dicts are not referenced and
2058209b8e3eSBram Moolenaar // there is no closure using it, we can free the funccall_T and what's
2059209b8e3eSBram Moolenaar // in it.
2060209b8e3eSBram Moolenaar if (may_free_fc && fc->l_avars.dv_refcount == DO_NOT_FREE_CNT)
2061209b8e3eSBram Moolenaar vars_clear_ext(&fc->l_avars.dv_hashtab, FALSE);
20626914c64eSBram Moolenaar else
20636914c64eSBram Moolenaar {
20646914c64eSBram Moolenaar int todo;
2065209b8e3eSBram Moolenaar hashitem_T *hi;
2066209b8e3eSBram Moolenaar dictitem_T *di;
20676914c64eSBram Moolenaar
2068209b8e3eSBram Moolenaar free_fc = FALSE;
20696914c64eSBram Moolenaar
2070209b8e3eSBram Moolenaar // Make a copy of the a: variables, since we didn't do that above.
20716914c64eSBram Moolenaar todo = (int)fc->l_avars.dv_hashtab.ht_used;
20726914c64eSBram Moolenaar for (hi = fc->l_avars.dv_hashtab.ht_array; todo > 0; ++hi)
20736914c64eSBram Moolenaar {
20746914c64eSBram Moolenaar if (!HASHITEM_EMPTY(hi))
20756914c64eSBram Moolenaar {
20766914c64eSBram Moolenaar --todo;
2077209b8e3eSBram Moolenaar di = HI2DI(hi);
2078209b8e3eSBram Moolenaar copy_tv(&di->di_tv, &di->di_tv);
2079209b8e3eSBram Moolenaar }
20806914c64eSBram Moolenaar }
20816914c64eSBram Moolenaar }
20826914c64eSBram Moolenaar
2083209b8e3eSBram Moolenaar if (may_free_fc && fc->l_varlist.lv_refcount == DO_NOT_FREE_CNT)
2084209b8e3eSBram Moolenaar fc->l_varlist.lv_first = NULL;
2085209b8e3eSBram Moolenaar else
2086209b8e3eSBram Moolenaar {
2087209b8e3eSBram Moolenaar listitem_T *li;
2088209b8e3eSBram Moolenaar
2089209b8e3eSBram Moolenaar free_fc = FALSE;
2090209b8e3eSBram Moolenaar
2091209b8e3eSBram Moolenaar // Make a copy of the a:000 items, since we didn't do that above.
2092aeea7215SBram Moolenaar FOR_ALL_LIST_ITEMS(&fc->l_varlist, li)
20936914c64eSBram Moolenaar copy_tv(&li->li_tv, &li->li_tv);
2094209b8e3eSBram Moolenaar }
20954456ab52SBram Moolenaar
2096209b8e3eSBram Moolenaar if (free_fc)
2097209b8e3eSBram Moolenaar free_funccal(fc);
2098209b8e3eSBram Moolenaar else
20994456ab52SBram Moolenaar {
2100209b8e3eSBram Moolenaar static int made_copy = 0;
2101209b8e3eSBram Moolenaar
2102209b8e3eSBram Moolenaar // "fc" is still in use. This can happen when returning "a:000",
2103209b8e3eSBram Moolenaar // assigning "l:" to a global variable or defining a closure.
2104209b8e3eSBram Moolenaar // Link "fc" in the list for garbage collection later.
2105209b8e3eSBram Moolenaar fc->caller = previous_funccal;
2106209b8e3eSBram Moolenaar previous_funccal = fc;
2107209b8e3eSBram Moolenaar
2108209b8e3eSBram Moolenaar if (want_garbage_collect)
2109209b8e3eSBram Moolenaar // If garbage collector is ready, clear count.
2110209b8e3eSBram Moolenaar made_copy = 0;
2111209b8e3eSBram Moolenaar else if (++made_copy >= (int)((4096 * 1024) / sizeof(*fc)))
2112209b8e3eSBram Moolenaar {
2113209b8e3eSBram Moolenaar // We have made a lot of copies, worth 4 Mbyte. This can happen
2114209b8e3eSBram Moolenaar // when repetitively calling a function that creates a reference to
2115889da2f2SBram Moolenaar // itself somehow. Call the garbage collector soon to avoid using
21164456ab52SBram Moolenaar // too much memory.
21174456ab52SBram Moolenaar made_copy = 0;
2118889da2f2SBram Moolenaar want_garbage_collect = TRUE;
21194456ab52SBram Moolenaar }
21206914c64eSBram Moolenaar }
21216914c64eSBram Moolenaar }
2122fdeab65dSBram Moolenaar
2123fdeab65dSBram Moolenaar /*
2124fdeab65dSBram Moolenaar * There are two kinds of function names:
2125fdeab65dSBram Moolenaar * 1. ordinary names, function defined with :function or :def
2126fdeab65dSBram Moolenaar * 2. numbered functions and lambdas
2127fdeab65dSBram Moolenaar * For the first we only count the name stored in func_hashtab as a reference,
2128fdeab65dSBram Moolenaar * using function() does not count as a reference, because the function is
2129fdeab65dSBram Moolenaar * looked up by name.
2130fdeab65dSBram Moolenaar */
2131a05e524fSBram Moolenaar int
func_name_refcount(char_u * name)2132fdeab65dSBram Moolenaar func_name_refcount(char_u *name)
2133fdeab65dSBram Moolenaar {
2134fdeab65dSBram Moolenaar return isdigit(*name) || *name == '<';
2135fdeab65dSBram Moolenaar }
2136fdeab65dSBram Moolenaar
21378a7d6542SBram Moolenaar /*
21388a7d6542SBram Moolenaar * Unreference "fc": decrement the reference count and free it when it
21398a7d6542SBram Moolenaar * becomes zero. "fp" is detached from "fc".
21408a7d6542SBram Moolenaar * When "force" is TRUE we are exiting.
21418a7d6542SBram Moolenaar */
21428a7d6542SBram Moolenaar static void
funccal_unref(funccall_T * fc,ufunc_T * fp,int force)21438a7d6542SBram Moolenaar funccal_unref(funccall_T *fc, ufunc_T *fp, int force)
21448a7d6542SBram Moolenaar {
21458a7d6542SBram Moolenaar funccall_T **pfc;
21468a7d6542SBram Moolenaar int i;
21478a7d6542SBram Moolenaar
21488a7d6542SBram Moolenaar if (fc == NULL)
21498a7d6542SBram Moolenaar return;
21508a7d6542SBram Moolenaar
21518a7d6542SBram Moolenaar if (--fc->fc_refcount <= 0 && (force || (
21528a7d6542SBram Moolenaar fc->l_varlist.lv_refcount == DO_NOT_FREE_CNT
21538a7d6542SBram Moolenaar && fc->l_vars.dv_refcount == DO_NOT_FREE_CNT
21548a7d6542SBram Moolenaar && fc->l_avars.dv_refcount == DO_NOT_FREE_CNT)))
21558a7d6542SBram Moolenaar for (pfc = &previous_funccal; *pfc != NULL; pfc = &(*pfc)->caller)
21568a7d6542SBram Moolenaar {
21578a7d6542SBram Moolenaar if (fc == *pfc)
21588a7d6542SBram Moolenaar {
21598a7d6542SBram Moolenaar *pfc = fc->caller;
21608a7d6542SBram Moolenaar free_funccal_contents(fc);
21618a7d6542SBram Moolenaar return;
21628a7d6542SBram Moolenaar }
21638a7d6542SBram Moolenaar }
21648a7d6542SBram Moolenaar for (i = 0; i < fc->fc_funcs.ga_len; ++i)
21658a7d6542SBram Moolenaar if (((ufunc_T **)(fc->fc_funcs.ga_data))[i] == fp)
21668a7d6542SBram Moolenaar ((ufunc_T **)(fc->fc_funcs.ga_data))[i] = NULL;
21678a7d6542SBram Moolenaar }
21688a7d6542SBram Moolenaar
21698a7d6542SBram Moolenaar /*
21708a7d6542SBram Moolenaar * Remove the function from the function hashtable. If the function was
21718a7d6542SBram Moolenaar * deleted while it still has references this was already done.
21728a7d6542SBram Moolenaar * Return TRUE if the entry was deleted, FALSE if it wasn't found.
21738a7d6542SBram Moolenaar */
21748a7d6542SBram Moolenaar static int
func_remove(ufunc_T * fp)21758a7d6542SBram Moolenaar func_remove(ufunc_T *fp)
21768a7d6542SBram Moolenaar {
21778a7d6542SBram Moolenaar hashitem_T *hi;
21788a7d6542SBram Moolenaar
21798a7d6542SBram Moolenaar // Return if it was already virtually deleted.
21808a7d6542SBram Moolenaar if (fp->uf_flags & FC_DEAD)
21818a7d6542SBram Moolenaar return FALSE;
21828a7d6542SBram Moolenaar
21838a7d6542SBram Moolenaar hi = hash_find(&func_hashtab, UF2HIKEY(fp));
21848a7d6542SBram Moolenaar if (!HASHITEM_EMPTY(hi))
21858a7d6542SBram Moolenaar {
21868a7d6542SBram Moolenaar // When there is a def-function index do not actually remove the
21878a7d6542SBram Moolenaar // function, so we can find the index when defining the function again.
218838ddf333SBram Moolenaar // Do remove it when it's a copy.
218938ddf333SBram Moolenaar if (fp->uf_def_status == UF_COMPILED && (fp->uf_flags & FC_COPY) == 0)
2190c970e422SBram Moolenaar {
21918a7d6542SBram Moolenaar fp->uf_flags |= FC_DEAD;
2192c970e422SBram Moolenaar return FALSE;
2193c970e422SBram Moolenaar }
21948a7d6542SBram Moolenaar hash_remove(&func_hashtab, hi);
2195c970e422SBram Moolenaar fp->uf_flags |= FC_DELETED;
21968a7d6542SBram Moolenaar return TRUE;
21978a7d6542SBram Moolenaar }
21988a7d6542SBram Moolenaar return FALSE;
21998a7d6542SBram Moolenaar }
22008a7d6542SBram Moolenaar
22018a7d6542SBram Moolenaar static void
func_clear_items(ufunc_T * fp)22028a7d6542SBram Moolenaar func_clear_items(ufunc_T *fp)
22038a7d6542SBram Moolenaar {
22048a7d6542SBram Moolenaar ga_clear_strings(&(fp->uf_args));
22058a7d6542SBram Moolenaar ga_clear_strings(&(fp->uf_def_args));
22068a7d6542SBram Moolenaar ga_clear_strings(&(fp->uf_lines));
22078a7d6542SBram Moolenaar VIM_CLEAR(fp->uf_arg_types);
2208fbbcd003SBram Moolenaar VIM_CLEAR(fp->uf_block_ids);
2209292b90d4SBram Moolenaar VIM_CLEAR(fp->uf_va_name);
22106110e79aSBram Moolenaar clear_type_list(&fp->uf_type_list);
22110d3de8cbSBram Moolenaar
22120d3de8cbSBram Moolenaar // Increment the refcount of this function to avoid it being freed
22130d3de8cbSBram Moolenaar // recursively when the partial is freed.
22140d3de8cbSBram Moolenaar fp->uf_refcount += 3;
2215f112f30aSBram Moolenaar partial_unref(fp->uf_partial);
2216f112f30aSBram Moolenaar fp->uf_partial = NULL;
22170d3de8cbSBram Moolenaar fp->uf_refcount -= 3;
2218801ab069SBram Moolenaar
2219801ab069SBram Moolenaar #ifdef FEAT_LUA
2220801ab069SBram Moolenaar if (fp->uf_cb_free != NULL)
2221801ab069SBram Moolenaar {
2222801ab069SBram Moolenaar fp->uf_cb_free(fp->uf_cb_state);
2223801ab069SBram Moolenaar fp->uf_cb_free = NULL;
2224801ab069SBram Moolenaar }
2225801ab069SBram Moolenaar
2226801ab069SBram Moolenaar fp->uf_cb_state = NULL;
2227801ab069SBram Moolenaar fp->uf_cb = NULL;
2228801ab069SBram Moolenaar #endif
22298a7d6542SBram Moolenaar #ifdef FEAT_PROFILE
22308a7d6542SBram Moolenaar VIM_CLEAR(fp->uf_tml_count);
22318a7d6542SBram Moolenaar VIM_CLEAR(fp->uf_tml_total);
22328a7d6542SBram Moolenaar VIM_CLEAR(fp->uf_tml_self);
22338a7d6542SBram Moolenaar #endif
22348a7d6542SBram Moolenaar }
22358a7d6542SBram Moolenaar
22368a7d6542SBram Moolenaar /*
22378a7d6542SBram Moolenaar * Free all things that a function contains. Does not free the function
22388a7d6542SBram Moolenaar * itself, use func_free() for that.
22398a7d6542SBram Moolenaar * When "force" is TRUE we are exiting.
22408a7d6542SBram Moolenaar */
22418a7d6542SBram Moolenaar static void
func_clear(ufunc_T * fp,int force)22428a7d6542SBram Moolenaar func_clear(ufunc_T *fp, int force)
22438a7d6542SBram Moolenaar {
22448a7d6542SBram Moolenaar if (fp->uf_cleared)
22458a7d6542SBram Moolenaar return;
22468a7d6542SBram Moolenaar fp->uf_cleared = TRUE;
22478a7d6542SBram Moolenaar
22488a7d6542SBram Moolenaar // clear this function
22498a7d6542SBram Moolenaar func_clear_items(fp);
22508a7d6542SBram Moolenaar funccal_unref(fp->uf_scoped, fp, force);
2251cd45ed03SBram Moolenaar unlink_def_function(fp);
22528a7d6542SBram Moolenaar }
22538a7d6542SBram Moolenaar
22548a7d6542SBram Moolenaar /*
22558a7d6542SBram Moolenaar * Free a function and remove it from the list of functions. Does not free
22568a7d6542SBram Moolenaar * what a function contains, call func_clear() first.
2257f7779c63SBram Moolenaar * When "force" is TRUE we are exiting.
2258a05e524fSBram Moolenaar * Returns OK when the function was actually freed.
22598a7d6542SBram Moolenaar */
2260a05e524fSBram Moolenaar static int
func_free(ufunc_T * fp,int force)2261f7779c63SBram Moolenaar func_free(ufunc_T *fp, int force)
22628a7d6542SBram Moolenaar {
22638a7d6542SBram Moolenaar // Only remove it when not done already, otherwise we would remove a newer
22648a7d6542SBram Moolenaar // version of the function with the same name.
22658a7d6542SBram Moolenaar if ((fp->uf_flags & (FC_DELETED | FC_REMOVED)) == 0)
22668a7d6542SBram Moolenaar func_remove(fp);
22678a7d6542SBram Moolenaar
2268f7779c63SBram Moolenaar if ((fp->uf_flags & FC_DEAD) == 0 || force)
2269c4ce36d4SBram Moolenaar {
2270fdeab65dSBram Moolenaar if (fp->uf_dfunc_idx > 0)
2271fdeab65dSBram Moolenaar unlink_def_function(fp);
2272c4ce36d4SBram Moolenaar VIM_CLEAR(fp->uf_name_exp);
22738a7d6542SBram Moolenaar vim_free(fp);
2274a05e524fSBram Moolenaar return OK;
22758a7d6542SBram Moolenaar }
2276a05e524fSBram Moolenaar return FAIL;
2277c4ce36d4SBram Moolenaar }
22788a7d6542SBram Moolenaar
22798a7d6542SBram Moolenaar /*
22808a7d6542SBram Moolenaar * Free all things that a function contains and free the function itself.
22818a7d6542SBram Moolenaar * When "force" is TRUE we are exiting.
22828a7d6542SBram Moolenaar */
22838a7d6542SBram Moolenaar static void
func_clear_free(ufunc_T * fp,int force)22848a7d6542SBram Moolenaar func_clear_free(ufunc_T *fp, int force)
22858a7d6542SBram Moolenaar {
22868a7d6542SBram Moolenaar func_clear(fp, force);
2287fdeab65dSBram Moolenaar if (force || fp->uf_dfunc_idx == 0 || func_name_refcount(fp->uf_name)
2288fdeab65dSBram Moolenaar || (fp->uf_flags & FC_COPY))
2289f7779c63SBram Moolenaar func_free(fp, force);
2290925e9fd6SBram Moolenaar else
2291925e9fd6SBram Moolenaar fp->uf_flags |= FC_DEAD;
22928a7d6542SBram Moolenaar }
22938a7d6542SBram Moolenaar
229438ddf333SBram Moolenaar /*
229538ddf333SBram Moolenaar * Copy already defined function "lambda" to a new function with name "global".
229638ddf333SBram Moolenaar * This is for when a compiled function defines a global function.
229738ddf333SBram Moolenaar */
2298cd45ed03SBram Moolenaar int
copy_func(char_u * lambda,char_u * global,ectx_T * ectx)2299cd45ed03SBram Moolenaar copy_func(char_u *lambda, char_u *global, ectx_T *ectx)
230038ddf333SBram Moolenaar {
230138ddf333SBram Moolenaar ufunc_T *ufunc = find_func_even_dead(lambda, TRUE, NULL);
2302f112f30aSBram Moolenaar ufunc_T *fp = NULL;
230338ddf333SBram Moolenaar
230438ddf333SBram Moolenaar if (ufunc == NULL)
230538ddf333SBram Moolenaar {
2306cd45ed03SBram Moolenaar semsg(_(e_lambda_function_not_found_str), lambda);
2307cd45ed03SBram Moolenaar return FAIL;
2308cd45ed03SBram Moolenaar }
2309cd45ed03SBram Moolenaar
231038ddf333SBram Moolenaar fp = find_func(global, TRUE, NULL);
231138ddf333SBram Moolenaar if (fp != NULL)
231238ddf333SBram Moolenaar {
23130d3de8cbSBram Moolenaar // TODO: handle ! to overwrite
231438ddf333SBram Moolenaar semsg(_(e_funcexts), global);
2315cd45ed03SBram Moolenaar return FAIL;
231638ddf333SBram Moolenaar }
231738ddf333SBram Moolenaar
231838ddf333SBram Moolenaar fp = alloc_clear(offsetof(ufunc_T, uf_name) + STRLEN(global) + 1);
231938ddf333SBram Moolenaar if (fp == NULL)
2320cd45ed03SBram Moolenaar return FAIL;
232138ddf333SBram Moolenaar
232238ddf333SBram Moolenaar fp->uf_varargs = ufunc->uf_varargs;
232338ddf333SBram Moolenaar fp->uf_flags = (ufunc->uf_flags & ~FC_VIM9) | FC_COPY;
232438ddf333SBram Moolenaar fp->uf_def_status = ufunc->uf_def_status;
232538ddf333SBram Moolenaar fp->uf_dfunc_idx = ufunc->uf_dfunc_idx;
2326af8edbb8SBram Moolenaar if (ga_copy_strings(&ufunc->uf_args, &fp->uf_args) == FAIL
2327af8edbb8SBram Moolenaar || ga_copy_strings(&ufunc->uf_def_args, &fp->uf_def_args)
232838ddf333SBram Moolenaar == FAIL
2329af8edbb8SBram Moolenaar || ga_copy_strings(&ufunc->uf_lines, &fp->uf_lines) == FAIL)
233038ddf333SBram Moolenaar goto failed;
233138ddf333SBram Moolenaar
233238ddf333SBram Moolenaar fp->uf_name_exp = ufunc->uf_name_exp == NULL ? NULL
233338ddf333SBram Moolenaar : vim_strsave(ufunc->uf_name_exp);
233438ddf333SBram Moolenaar if (ufunc->uf_arg_types != NULL)
233538ddf333SBram Moolenaar {
233638ddf333SBram Moolenaar fp->uf_arg_types = ALLOC_MULT(type_T *, fp->uf_args.ga_len);
233738ddf333SBram Moolenaar if (fp->uf_arg_types == NULL)
233838ddf333SBram Moolenaar goto failed;
233938ddf333SBram Moolenaar mch_memmove(fp->uf_arg_types, ufunc->uf_arg_types,
234038ddf333SBram Moolenaar sizeof(type_T *) * fp->uf_args.ga_len);
234138ddf333SBram Moolenaar }
234238ddf333SBram Moolenaar if (ufunc->uf_va_name != NULL)
234338ddf333SBram Moolenaar {
234438ddf333SBram Moolenaar fp->uf_va_name = vim_strsave(ufunc->uf_va_name);
234538ddf333SBram Moolenaar if (fp->uf_va_name == NULL)
234638ddf333SBram Moolenaar goto failed;
234738ddf333SBram Moolenaar }
2348f112f30aSBram Moolenaar fp->uf_ret_type = ufunc->uf_ret_type;
234938ddf333SBram Moolenaar
235038ddf333SBram Moolenaar fp->uf_refcount = 1;
235138ddf333SBram Moolenaar STRCPY(fp->uf_name, global);
235238ddf333SBram Moolenaar hash_add(&func_hashtab, UF2HIKEY(fp));
2353cd45ed03SBram Moolenaar
2354cd45ed03SBram Moolenaar // the referenced dfunc_T is now used one more time
2355cd45ed03SBram Moolenaar link_def_function(fp);
2356cd45ed03SBram Moolenaar
23570d3de8cbSBram Moolenaar // Create a partial to store the context of the function where it was
23580d3de8cbSBram Moolenaar // instantiated. Only needs to be done once. Do this on the original
23590d3de8cbSBram Moolenaar // function, "dfunc->df_ufunc" will point to it.
2360cd45ed03SBram Moolenaar if ((ufunc->uf_flags & FC_CLOSURE) && ufunc->uf_partial == NULL)
2361cd45ed03SBram Moolenaar {
2362cd45ed03SBram Moolenaar partial_T *pt = ALLOC_CLEAR_ONE(partial_T);
2363cd45ed03SBram Moolenaar
2364cd45ed03SBram Moolenaar if (pt == NULL)
2365cd45ed03SBram Moolenaar goto failed;
2366cd45ed03SBram Moolenaar if (fill_partial_and_closure(pt, ufunc, ectx) == FAIL)
2367cd45ed03SBram Moolenaar {
23680d3de8cbSBram Moolenaar vim_free(pt);
23690d3de8cbSBram Moolenaar goto failed;
23700d3de8cbSBram Moolenaar }
23710d3de8cbSBram Moolenaar ufunc->uf_partial = pt;
23720d3de8cbSBram Moolenaar --pt->pt_refcount; // not actually referenced here
2373cd45ed03SBram Moolenaar }
2374cd45ed03SBram Moolenaar
2375cd45ed03SBram Moolenaar return OK;
237638ddf333SBram Moolenaar
237738ddf333SBram Moolenaar failed:
237838ddf333SBram Moolenaar func_clear_free(fp, TRUE);
2379cd45ed03SBram Moolenaar return FAIL;
238038ddf333SBram Moolenaar }
238138ddf333SBram Moolenaar
23820ba48e8cSBram Moolenaar static int funcdepth = 0;
23830ba48e8cSBram Moolenaar
23840ba48e8cSBram Moolenaar /*
23850ba48e8cSBram Moolenaar * Increment the function call depth count.
23860ba48e8cSBram Moolenaar * Return FAIL when going over 'maxfuncdepth'.
23870ba48e8cSBram Moolenaar * Otherwise return OK, must call funcdepth_decrement() later!
23880ba48e8cSBram Moolenaar */
23890ba48e8cSBram Moolenaar int
funcdepth_increment(void)23900ba48e8cSBram Moolenaar funcdepth_increment(void)
23910ba48e8cSBram Moolenaar {
23920ba48e8cSBram Moolenaar if (funcdepth >= p_mfd)
23930ba48e8cSBram Moolenaar {
23940ba48e8cSBram Moolenaar emsg(_("E132: Function call depth is higher than 'maxfuncdepth'"));
23950ba48e8cSBram Moolenaar return FAIL;
23960ba48e8cSBram Moolenaar }
23970ba48e8cSBram Moolenaar ++funcdepth;
23980ba48e8cSBram Moolenaar return OK;
23990ba48e8cSBram Moolenaar }
24000ba48e8cSBram Moolenaar
24010ba48e8cSBram Moolenaar void
funcdepth_decrement(void)24020ba48e8cSBram Moolenaar funcdepth_decrement(void)
24030ba48e8cSBram Moolenaar {
24040ba48e8cSBram Moolenaar --funcdepth;
24050ba48e8cSBram Moolenaar }
24060ba48e8cSBram Moolenaar
24070ba48e8cSBram Moolenaar /*
24080ba48e8cSBram Moolenaar * Get the current function call depth.
24090ba48e8cSBram Moolenaar */
24100ba48e8cSBram Moolenaar int
funcdepth_get(void)24110ba48e8cSBram Moolenaar funcdepth_get(void)
24120ba48e8cSBram Moolenaar {
24130ba48e8cSBram Moolenaar return funcdepth;
24140ba48e8cSBram Moolenaar }
24150ba48e8cSBram Moolenaar
24160ba48e8cSBram Moolenaar /*
24170ba48e8cSBram Moolenaar * Restore the function call depth. This is for cases where there is no
24188e7d6223SBram Moolenaar * guarantee funcdepth_decrement() can be called exactly the same number of
24190ba48e8cSBram Moolenaar * times as funcdepth_increment().
24200ba48e8cSBram Moolenaar */
24210ba48e8cSBram Moolenaar void
funcdepth_restore(int depth)24220ba48e8cSBram Moolenaar funcdepth_restore(int depth)
24230ba48e8cSBram Moolenaar {
24240ba48e8cSBram Moolenaar funcdepth = depth;
24250ba48e8cSBram Moolenaar }
24266914c64eSBram Moolenaar
24276914c64eSBram Moolenaar /*
2428a9b579f3SBram Moolenaar * Call a user function.
2429a9b579f3SBram Moolenaar */
2430a9b579f3SBram Moolenaar static void
call_user_func(ufunc_T * fp,int argcount,typval_T * argvars,typval_T * rettv,funcexe_T * funcexe,dict_T * selfdict)2431a9b579f3SBram Moolenaar call_user_func(
2432e38eab22SBram Moolenaar ufunc_T *fp, // pointer to function
2433e38eab22SBram Moolenaar int argcount, // nr of args
2434e38eab22SBram Moolenaar typval_T *argvars, // arguments
2435e38eab22SBram Moolenaar typval_T *rettv, // return value
24366f5b6dfbSBram Moolenaar funcexe_T *funcexe, // context
2437e38eab22SBram Moolenaar dict_T *selfdict) // Dictionary for "self"
2438a9b579f3SBram Moolenaar {
2439f29c1c6aSBram Moolenaar sctx_T save_current_sctx;
244093343725SBram Moolenaar int using_sandbox = FALSE;
2441a9b579f3SBram Moolenaar funccall_T *fc;
2442a9b579f3SBram Moolenaar int save_did_emsg;
244342ae78cfSBram Moolenaar int default_arg_err = FALSE;
2444a9b579f3SBram Moolenaar dictitem_T *v;
2445e38eab22SBram Moolenaar int fixvar_idx = 0; // index in fixvar[]
2446a9b579f3SBram Moolenaar int i;
2447a9b579f3SBram Moolenaar int ai;
2448a9b579f3SBram Moolenaar int islambda = FALSE;
2449a9b579f3SBram Moolenaar char_u numbuf[NUMBUFLEN];
2450a9b579f3SBram Moolenaar char_u *name;
2451b47bed2fSBram Moolenaar typval_T *tv_to_free[MAX_FUNC_ARGS];
2452b47bed2fSBram Moolenaar int tv_to_free_len = 0;
2453a9b579f3SBram Moolenaar #ifdef FEAT_PROFILE
2454b2049903SBram Moolenaar profinfo_T profile_info;
2455a9b579f3SBram Moolenaar #endif
2456e31ee868SBram Moolenaar ESTACK_CHECK_DECLARATION
2457a9b579f3SBram Moolenaar
2458b2049903SBram Moolenaar #ifdef FEAT_PROFILE
2459b2049903SBram Moolenaar CLEAR_FIELD(profile_info);
2460b2049903SBram Moolenaar #endif
2461b2049903SBram Moolenaar
24620ba48e8cSBram Moolenaar // If depth of calling is getting too high, don't execute the function.
24630ba48e8cSBram Moolenaar if (funcdepth_increment() == FAIL)
2464a9b579f3SBram Moolenaar {
2465a9b579f3SBram Moolenaar rettv->v_type = VAR_NUMBER;
2466a9b579f3SBram Moolenaar rettv->vval.v_number = -1;
2467a9b579f3SBram Moolenaar return;
2468a9b579f3SBram Moolenaar }
2469a9b579f3SBram Moolenaar
2470e38eab22SBram Moolenaar line_breakcheck(); // check for CTRL-C hit
2471a9b579f3SBram Moolenaar
2472c799fe20SBram Moolenaar fc = ALLOC_CLEAR_ONE(funccall_T);
24734456ab52SBram Moolenaar if (fc == NULL)
24744456ab52SBram Moolenaar return;
2475a9b579f3SBram Moolenaar fc->caller = current_funccal;
2476a9b579f3SBram Moolenaar current_funccal = fc;
2477a9b579f3SBram Moolenaar fc->func = fp;
2478a9b579f3SBram Moolenaar fc->rettv = rettv;
2479a9b579f3SBram Moolenaar fc->level = ex_nesting_level;
2480e38eab22SBram Moolenaar // Check if this function has a breakpoint.
2481a9b579f3SBram Moolenaar fc->breakpoint = dbg_find_breakpoint(FALSE, fp->uf_name, (linenr_T)0);
2482a9b579f3SBram Moolenaar fc->dbg_tick = debug_tick;
2483e38eab22SBram Moolenaar // Set up fields for closure.
24841e96d9bfSBram Moolenaar ga_init2(&fc->fc_funcs, sizeof(ufunc_T *), 1);
2485437bafe4SBram Moolenaar func_ptr_ref(fp);
2486a9b579f3SBram Moolenaar
24870cb5bcf5SBram Moolenaar if (fp->uf_def_status != UF_NOT_COMPILED)
24888a7d6542SBram Moolenaar {
248912d26531SBram Moolenaar #ifdef FEAT_PROFILE
249012d26531SBram Moolenaar ufunc_T *caller = fc->caller == NULL ? NULL : fc->caller->func;
249112d26531SBram Moolenaar #endif
249225e0f586SBram Moolenaar // Execute the function, possibly compiling it first.
2493b2049903SBram Moolenaar #ifdef FEAT_PROFILE
249412d26531SBram Moolenaar if (do_profiling == PROF_YES)
249512d26531SBram Moolenaar profile_may_start_func(&profile_info, fp, caller);
2496b2049903SBram Moolenaar #endif
24976f5b6dfbSBram Moolenaar call_def_function(fp, argcount, argvars, funcexe->partial, rettv);
24980ba48e8cSBram Moolenaar funcdepth_decrement();
2499b2049903SBram Moolenaar #ifdef FEAT_PROFILE
2500b2049903SBram Moolenaar if (do_profiling == PROF_YES && (fp->uf_profiling
250112d26531SBram Moolenaar || (caller != NULL && caller->uf_profiling)))
250212d26531SBram Moolenaar profile_may_end_func(&profile_info, fp, caller);
2503b2049903SBram Moolenaar #endif
25048a7d6542SBram Moolenaar current_funccal = fc->caller;
25058a7d6542SBram Moolenaar free_funccal(fc);
25068a7d6542SBram Moolenaar return;
25078a7d6542SBram Moolenaar }
25088a7d6542SBram Moolenaar
2509a9b579f3SBram Moolenaar if (STRNCMP(fp->uf_name, "<lambda>", 8) == 0)
2510a9b579f3SBram Moolenaar islambda = TRUE;
2511a9b579f3SBram Moolenaar
2512a9b579f3SBram Moolenaar /*
2513a9b579f3SBram Moolenaar * Note about using fc->fixvar[]: This is an array of FIXVAR_CNT variables
2514a9b579f3SBram Moolenaar * with names up to VAR_SHORT_LEN long. This avoids having to alloc/free
2515a9b579f3SBram Moolenaar * each argument variable and saves a lot of time.
2516a9b579f3SBram Moolenaar */
2517a9b579f3SBram Moolenaar /*
2518a9b579f3SBram Moolenaar * Init l: variables.
2519a9b579f3SBram Moolenaar */
2520a9b579f3SBram Moolenaar init_var_dict(&fc->l_vars, &fc->l_vars_var, VAR_DEF_SCOPE);
2521a9b579f3SBram Moolenaar if (selfdict != NULL)
2522a9b579f3SBram Moolenaar {
2523e38eab22SBram Moolenaar // Set l:self to "selfdict". Use "name" to avoid a warning from
2524e38eab22SBram Moolenaar // some compiler that checks the destination size.
2525a9b579f3SBram Moolenaar v = &fc->fixvar[fixvar_idx++].var;
2526a9b579f3SBram Moolenaar name = v->di_key;
2527a9b579f3SBram Moolenaar STRCPY(name, "self");
252831b81604SBram Moolenaar v->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX;
2529a9b579f3SBram Moolenaar hash_add(&fc->l_vars.dv_hashtab, DI2HIKEY(v));
2530a9b579f3SBram Moolenaar v->di_tv.v_type = VAR_DICT;
2531a9b579f3SBram Moolenaar v->di_tv.v_lock = 0;
2532a9b579f3SBram Moolenaar v->di_tv.vval.v_dict = selfdict;
2533a9b579f3SBram Moolenaar ++selfdict->dv_refcount;
2534a9b579f3SBram Moolenaar }
2535a9b579f3SBram Moolenaar
2536a9b579f3SBram Moolenaar /*
2537f10806b2SBram Moolenaar * Init a: variables, unless none found (in lambda).
253842ae78cfSBram Moolenaar * Set a:0 to "argcount" less number of named arguments, if >= 0.
2539a9b579f3SBram Moolenaar * Set a:000 to a list with room for the "..." arguments.
2540a9b579f3SBram Moolenaar */
2541a9b579f3SBram Moolenaar init_var_dict(&fc->l_avars, &fc->l_avars_var, VAR_SCOPE);
2542f10806b2SBram Moolenaar if ((fp->uf_flags & FC_NOARGS) == 0)
2543a9b579f3SBram Moolenaar add_nr_var(&fc->l_avars, &fc->fixvar[fixvar_idx++].var, "0",
254442ae78cfSBram Moolenaar (varnumber_T)(argcount >= fp->uf_args.ga_len
254542ae78cfSBram Moolenaar ? argcount - fp->uf_args.ga_len : 0));
254631b81604SBram Moolenaar fc->l_avars.dv_lock = VAR_FIXED;
2547f10806b2SBram Moolenaar if ((fp->uf_flags & FC_NOARGS) == 0)
2548f10806b2SBram Moolenaar {
2549e38eab22SBram Moolenaar // Use "name" to avoid a warning from some compiler that checks the
2550e38eab22SBram Moolenaar // destination size.
2551a9b579f3SBram Moolenaar v = &fc->fixvar[fixvar_idx++].var;
2552a9b579f3SBram Moolenaar name = v->di_key;
2553a9b579f3SBram Moolenaar STRCPY(name, "000");
2554a9b579f3SBram Moolenaar v->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX;
2555a9b579f3SBram Moolenaar hash_add(&fc->l_avars.dv_hashtab, DI2HIKEY(v));
2556a9b579f3SBram Moolenaar v->di_tv.v_type = VAR_LIST;
2557a9b579f3SBram Moolenaar v->di_tv.v_lock = VAR_FIXED;
2558a9b579f3SBram Moolenaar v->di_tv.vval.v_list = &fc->l_varlist;
2559f10806b2SBram Moolenaar }
2560a80faa89SBram Moolenaar CLEAR_FIELD(fc->l_varlist);
2561a9b579f3SBram Moolenaar fc->l_varlist.lv_refcount = DO_NOT_FREE_CNT;
2562a9b579f3SBram Moolenaar fc->l_varlist.lv_lock = VAR_FIXED;
2563a9b579f3SBram Moolenaar
2564a9b579f3SBram Moolenaar /*
2565a9b579f3SBram Moolenaar * Set a:firstline to "firstline" and a:lastline to "lastline".
2566a9b579f3SBram Moolenaar * Set a:name to named arguments.
2567a9b579f3SBram Moolenaar * Set a:N to the "..." arguments.
2568f10806b2SBram Moolenaar * Skipped when no a: variables used (in lambda).
2569a9b579f3SBram Moolenaar */
2570f10806b2SBram Moolenaar if ((fp->uf_flags & FC_NOARGS) == 0)
2571f10806b2SBram Moolenaar {
2572a9b579f3SBram Moolenaar add_nr_var(&fc->l_avars, &fc->fixvar[fixvar_idx++].var, "firstline",
25736f5b6dfbSBram Moolenaar (varnumber_T)funcexe->firstline);
2574a9b579f3SBram Moolenaar add_nr_var(&fc->l_avars, &fc->fixvar[fixvar_idx++].var, "lastline",
25756f5b6dfbSBram Moolenaar (varnumber_T)funcexe->lastline);
2576f10806b2SBram Moolenaar }
257742ae78cfSBram Moolenaar for (i = 0; i < argcount || i < fp->uf_args.ga_len; ++i)
2578a9b579f3SBram Moolenaar {
2579a9b579f3SBram Moolenaar int addlocal = FALSE;
258042ae78cfSBram Moolenaar typval_T def_rettv;
258142ae78cfSBram Moolenaar int isdefault = FALSE;
2582a9b579f3SBram Moolenaar
2583a9b579f3SBram Moolenaar ai = i - fp->uf_args.ga_len;
2584a9b579f3SBram Moolenaar if (ai < 0)
2585a9b579f3SBram Moolenaar {
2586e38eab22SBram Moolenaar // named argument a:name
2587a9b579f3SBram Moolenaar name = FUNCARG(fp, i);
2588a9b579f3SBram Moolenaar if (islambda)
2589a9b579f3SBram Moolenaar addlocal = TRUE;
259042ae78cfSBram Moolenaar
259142ae78cfSBram Moolenaar // evaluate named argument default expression
259242ae78cfSBram Moolenaar isdefault = ai + fp->uf_def_args.ga_len >= 0
259342ae78cfSBram Moolenaar && (i >= argcount || (argvars[i].v_type == VAR_SPECIAL
259442ae78cfSBram Moolenaar && argvars[i].vval.v_number == VVAL_NONE));
259542ae78cfSBram Moolenaar if (isdefault)
259642ae78cfSBram Moolenaar {
259742ae78cfSBram Moolenaar char_u *default_expr = NULL;
2598b47bed2fSBram Moolenaar
259942ae78cfSBram Moolenaar def_rettv.v_type = VAR_NUMBER;
260042ae78cfSBram Moolenaar def_rettv.vval.v_number = -1;
260142ae78cfSBram Moolenaar
260242ae78cfSBram Moolenaar default_expr = ((char_u **)(fp->uf_def_args.ga_data))
260342ae78cfSBram Moolenaar [ai + fp->uf_def_args.ga_len];
26045409f5d8SBram Moolenaar if (eval1(&default_expr, &def_rettv, &EVALARG_EVALUATE) == FAIL)
260542ae78cfSBram Moolenaar {
260642ae78cfSBram Moolenaar default_arg_err = 1;
260742ae78cfSBram Moolenaar break;
260842ae78cfSBram Moolenaar }
260942ae78cfSBram Moolenaar }
2610a9b579f3SBram Moolenaar }
2611a9b579f3SBram Moolenaar else
2612a9b579f3SBram Moolenaar {
2613f10806b2SBram Moolenaar if ((fp->uf_flags & FC_NOARGS) != 0)
2614f10806b2SBram Moolenaar // Bail out if no a: arguments used (in lambda).
2615f10806b2SBram Moolenaar break;
2616f10806b2SBram Moolenaar
2617e38eab22SBram Moolenaar // "..." argument a:1, a:2, etc.
2618a9b579f3SBram Moolenaar sprintf((char *)numbuf, "%d", ai + 1);
2619a9b579f3SBram Moolenaar name = numbuf;
2620a9b579f3SBram Moolenaar }
2621a9b579f3SBram Moolenaar if (fixvar_idx < FIXVAR_CNT && STRLEN(name) <= VAR_SHORT_LEN)
2622a9b579f3SBram Moolenaar {
2623a9b579f3SBram Moolenaar v = &fc->fixvar[fixvar_idx++].var;
2624a9b579f3SBram Moolenaar v->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX;
2625209b8e3eSBram Moolenaar STRCPY(v->di_key, name);
2626a9b579f3SBram Moolenaar }
2627a9b579f3SBram Moolenaar else
2628a9b579f3SBram Moolenaar {
2629209b8e3eSBram Moolenaar v = dictitem_alloc(name);
2630a9b579f3SBram Moolenaar if (v == NULL)
2631a9b579f3SBram Moolenaar break;
2632209b8e3eSBram Moolenaar v->di_flags |= DI_FLAGS_RO | DI_FLAGS_FIX;
2633a9b579f3SBram Moolenaar }
2634a9b579f3SBram Moolenaar
263542ae78cfSBram Moolenaar // Note: the values are copied directly to avoid alloc/free.
263642ae78cfSBram Moolenaar // "argvars" must have VAR_FIXED for v_lock.
26376e5000d4SBram Moolenaar v->di_tv = isdefault ? def_rettv : argvars[i];
2638a9b579f3SBram Moolenaar v->di_tv.v_lock = VAR_FIXED;
2639a9b579f3SBram Moolenaar
2640b47bed2fSBram Moolenaar if (isdefault)
2641b47bed2fSBram Moolenaar // Need to free this later, no matter where it's stored.
2642b47bed2fSBram Moolenaar tv_to_free[tv_to_free_len++] = &v->di_tv;
2643b47bed2fSBram Moolenaar
2644a9b579f3SBram Moolenaar if (addlocal)
2645a9b579f3SBram Moolenaar {
2646e38eab22SBram Moolenaar // Named arguments should be accessed without the "a:" prefix in
2647e38eab22SBram Moolenaar // lambda expressions. Add to the l: dict.
26481e96d9bfSBram Moolenaar copy_tv(&v->di_tv, &v->di_tv);
26491e96d9bfSBram Moolenaar hash_add(&fc->l_vars.dv_hashtab, DI2HIKEY(v));
2650a9b579f3SBram Moolenaar }
26511e96d9bfSBram Moolenaar else
26521e96d9bfSBram Moolenaar hash_add(&fc->l_avars.dv_hashtab, DI2HIKEY(v));
2653a9b579f3SBram Moolenaar
2654a9b579f3SBram Moolenaar if (ai >= 0 && ai < MAX_FUNC_ARGS)
2655a9b579f3SBram Moolenaar {
2656209b8e3eSBram Moolenaar listitem_T *li = &fc->l_listitems[ai];
2657209b8e3eSBram Moolenaar
2658209b8e3eSBram Moolenaar li->li_tv = argvars[i];
2659209b8e3eSBram Moolenaar li->li_tv.v_lock = VAR_FIXED;
2660209b8e3eSBram Moolenaar list_append(&fc->l_varlist, li);
2661a9b579f3SBram Moolenaar }
2662a9b579f3SBram Moolenaar }
2663a9b579f3SBram Moolenaar
2664e38eab22SBram Moolenaar // Don't redraw while executing the function.
2665a9b579f3SBram Moolenaar ++RedrawingDisabled;
266693343725SBram Moolenaar
266793343725SBram Moolenaar if (fp->uf_flags & FC_SANDBOX)
266893343725SBram Moolenaar {
266993343725SBram Moolenaar using_sandbox = TRUE;
267093343725SBram Moolenaar ++sandbox;
267193343725SBram Moolenaar }
267293343725SBram Moolenaar
267325e0f586SBram Moolenaar estack_push_ufunc(fp, 1);
2674e31ee868SBram Moolenaar ESTACK_CHECK_SETUP
2675a9b579f3SBram Moolenaar if (p_verbose >= 12)
2676a9b579f3SBram Moolenaar {
2677a9b579f3SBram Moolenaar ++no_wait_return;
2678a9b579f3SBram Moolenaar verbose_enter_scroll();
2679a9b579f3SBram Moolenaar
26801a47ae32SBram Moolenaar smsg(_("calling %s"), SOURCING_NAME);
2681a9b579f3SBram Moolenaar if (p_verbose >= 14)
2682a9b579f3SBram Moolenaar {
2683a9b579f3SBram Moolenaar char_u buf[MSG_BUF_LEN];
2684a9b579f3SBram Moolenaar char_u numbuf2[NUMBUFLEN];
2685a9b579f3SBram Moolenaar char_u *tofree;
2686a9b579f3SBram Moolenaar char_u *s;
2687a9b579f3SBram Moolenaar
268832526b3cSBram Moolenaar msg_puts("(");
2689a9b579f3SBram Moolenaar for (i = 0; i < argcount; ++i)
2690a9b579f3SBram Moolenaar {
2691a9b579f3SBram Moolenaar if (i > 0)
269232526b3cSBram Moolenaar msg_puts(", ");
2693a9b579f3SBram Moolenaar if (argvars[i].v_type == VAR_NUMBER)
2694a9b579f3SBram Moolenaar msg_outnum((long)argvars[i].vval.v_number);
2695a9b579f3SBram Moolenaar else
2696a9b579f3SBram Moolenaar {
2697e38eab22SBram Moolenaar // Do not want errors such as E724 here.
2698a9b579f3SBram Moolenaar ++emsg_off;
2699a9b579f3SBram Moolenaar s = tv2string(&argvars[i], &tofree, numbuf2, 0);
2700a9b579f3SBram Moolenaar --emsg_off;
2701a9b579f3SBram Moolenaar if (s != NULL)
2702a9b579f3SBram Moolenaar {
2703a9b579f3SBram Moolenaar if (vim_strsize(s) > MSG_BUF_CLEN)
2704a9b579f3SBram Moolenaar {
2705a9b579f3SBram Moolenaar trunc_string(s, buf, MSG_BUF_CLEN, MSG_BUF_LEN);
2706a9b579f3SBram Moolenaar s = buf;
2707a9b579f3SBram Moolenaar }
270832526b3cSBram Moolenaar msg_puts((char *)s);
2709a9b579f3SBram Moolenaar vim_free(tofree);
2710a9b579f3SBram Moolenaar }
2711a9b579f3SBram Moolenaar }
2712a9b579f3SBram Moolenaar }
271332526b3cSBram Moolenaar msg_puts(")");
2714a9b579f3SBram Moolenaar }
2715e38eab22SBram Moolenaar msg_puts("\n"); // don't overwrite this either
2716a9b579f3SBram Moolenaar
2717a9b579f3SBram Moolenaar verbose_leave_scroll();
2718a9b579f3SBram Moolenaar --no_wait_return;
2719a9b579f3SBram Moolenaar }
2720a9b579f3SBram Moolenaar #ifdef FEAT_PROFILE
272112d26531SBram Moolenaar if (do_profiling == PROF_YES)
272212d26531SBram Moolenaar profile_may_start_func(&profile_info, fp,
272312d26531SBram Moolenaar fc->caller == NULL ? NULL : fc->caller->func);
2724a9b579f3SBram Moolenaar #endif
2725a9b579f3SBram Moolenaar
2726f29c1c6aSBram Moolenaar save_current_sctx = current_sctx;
2727f29c1c6aSBram Moolenaar current_sctx = fp->uf_script_ctx;
2728a9b579f3SBram Moolenaar save_did_emsg = did_emsg;
2729a9b579f3SBram Moolenaar did_emsg = FALSE;
2730a9b579f3SBram Moolenaar
273142ae78cfSBram Moolenaar if (default_arg_err && (fp->uf_flags & FC_ABORT))
273242ae78cfSBram Moolenaar did_emsg = TRUE;
2733f10806b2SBram Moolenaar else if (islambda)
2734f10806b2SBram Moolenaar {
2735f10806b2SBram Moolenaar char_u *p = *(char_u **)fp->uf_lines.ga_data + 7;
2736f10806b2SBram Moolenaar
2737f10806b2SBram Moolenaar // A Lambda always has the command "return {expr}". It is much faster
2738f10806b2SBram Moolenaar // to evaluate {expr} directly.
2739f10806b2SBram Moolenaar ++ex_nesting_level;
27405409f5d8SBram Moolenaar (void)eval1(&p, rettv, &EVALARG_EVALUATE);
2741f10806b2SBram Moolenaar --ex_nesting_level;
2742f10806b2SBram Moolenaar }
274342ae78cfSBram Moolenaar else
274442ae78cfSBram Moolenaar // call do_cmdline() to execute the lines
2745a9b579f3SBram Moolenaar do_cmdline(NULL, get_func_line, (void *)fc,
2746a9b579f3SBram Moolenaar DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT);
2747a9b579f3SBram Moolenaar
2748a9b579f3SBram Moolenaar --RedrawingDisabled;
2749a9b579f3SBram Moolenaar
2750e38eab22SBram Moolenaar // when the function was aborted because of an error, return -1
2751a9b579f3SBram Moolenaar if ((did_emsg && (fp->uf_flags & FC_ABORT)) || rettv->v_type == VAR_UNKNOWN)
2752a9b579f3SBram Moolenaar {
2753a9b579f3SBram Moolenaar clear_tv(rettv);
2754a9b579f3SBram Moolenaar rettv->v_type = VAR_NUMBER;
2755a9b579f3SBram Moolenaar rettv->vval.v_number = -1;
2756a9b579f3SBram Moolenaar }
2757a9b579f3SBram Moolenaar
2758a9b579f3SBram Moolenaar #ifdef FEAT_PROFILE
275912d26531SBram Moolenaar if (do_profiling == PROF_YES)
276012d26531SBram Moolenaar {
276112d26531SBram Moolenaar ufunc_T *caller = fc->caller == NULL ? NULL : fc->caller->func;
276212d26531SBram Moolenaar
276312d26531SBram Moolenaar if (fp->uf_profiling || (caller != NULL && caller->uf_profiling))
276412d26531SBram Moolenaar profile_may_end_func(&profile_info, fp, caller);
276512d26531SBram Moolenaar }
2766a9b579f3SBram Moolenaar #endif
2767a9b579f3SBram Moolenaar
2768e38eab22SBram Moolenaar // when being verbose, mention the return value
2769a9b579f3SBram Moolenaar if (p_verbose >= 12)
2770a9b579f3SBram Moolenaar {
2771a9b579f3SBram Moolenaar ++no_wait_return;
2772a9b579f3SBram Moolenaar verbose_enter_scroll();
2773a9b579f3SBram Moolenaar
2774a9b579f3SBram Moolenaar if (aborting())
27751a47ae32SBram Moolenaar smsg(_("%s aborted"), SOURCING_NAME);
2776a9b579f3SBram Moolenaar else if (fc->rettv->v_type == VAR_NUMBER)
27771a47ae32SBram Moolenaar smsg(_("%s returning #%ld"), SOURCING_NAME,
2778a9b579f3SBram Moolenaar (long)fc->rettv->vval.v_number);
2779a9b579f3SBram Moolenaar else
2780a9b579f3SBram Moolenaar {
2781a9b579f3SBram Moolenaar char_u buf[MSG_BUF_LEN];
2782a9b579f3SBram Moolenaar char_u numbuf2[NUMBUFLEN];
2783a9b579f3SBram Moolenaar char_u *tofree;
2784a9b579f3SBram Moolenaar char_u *s;
2785a9b579f3SBram Moolenaar
2786e38eab22SBram Moolenaar // The value may be very long. Skip the middle part, so that we
2787e38eab22SBram Moolenaar // have some idea how it starts and ends. smsg() would always
2788e38eab22SBram Moolenaar // truncate it at the end. Don't want errors such as E724 here.
2789a9b579f3SBram Moolenaar ++emsg_off;
2790a9b579f3SBram Moolenaar s = tv2string(fc->rettv, &tofree, numbuf2, 0);
2791a9b579f3SBram Moolenaar --emsg_off;
2792a9b579f3SBram Moolenaar if (s != NULL)
2793a9b579f3SBram Moolenaar {
2794a9b579f3SBram Moolenaar if (vim_strsize(s) > MSG_BUF_CLEN)
2795a9b579f3SBram Moolenaar {
2796a9b579f3SBram Moolenaar trunc_string(s, buf, MSG_BUF_CLEN, MSG_BUF_LEN);
2797a9b579f3SBram Moolenaar s = buf;
2798a9b579f3SBram Moolenaar }
27991a47ae32SBram Moolenaar smsg(_("%s returning %s"), SOURCING_NAME, s);
2800a9b579f3SBram Moolenaar vim_free(tofree);
2801a9b579f3SBram Moolenaar }
2802a9b579f3SBram Moolenaar }
2803e38eab22SBram Moolenaar msg_puts("\n"); // don't overwrite this either
2804a9b579f3SBram Moolenaar
2805a9b579f3SBram Moolenaar verbose_leave_scroll();
2806a9b579f3SBram Moolenaar --no_wait_return;
2807a9b579f3SBram Moolenaar }
2808a9b579f3SBram Moolenaar
2809e31ee868SBram Moolenaar ESTACK_CHECK_NOW
28101a47ae32SBram Moolenaar estack_pop();
2811f29c1c6aSBram Moolenaar current_sctx = save_current_sctx;
2812a9b579f3SBram Moolenaar #ifdef FEAT_PROFILE
2813a9b579f3SBram Moolenaar if (do_profiling == PROF_YES)
2814b2049903SBram Moolenaar script_prof_restore(&profile_info.pi_wait_start);
2815a9b579f3SBram Moolenaar #endif
281693343725SBram Moolenaar if (using_sandbox)
281793343725SBram Moolenaar --sandbox;
2818a9b579f3SBram Moolenaar
28191a47ae32SBram Moolenaar if (p_verbose >= 12 && SOURCING_NAME != NULL)
2820a9b579f3SBram Moolenaar {
2821a9b579f3SBram Moolenaar ++no_wait_return;
2822a9b579f3SBram Moolenaar verbose_enter_scroll();
2823a9b579f3SBram Moolenaar
28241a47ae32SBram Moolenaar smsg(_("continuing in %s"), SOURCING_NAME);
2825e38eab22SBram Moolenaar msg_puts("\n"); // don't overwrite this either
2826a9b579f3SBram Moolenaar
2827a9b579f3SBram Moolenaar verbose_leave_scroll();
2828a9b579f3SBram Moolenaar --no_wait_return;
2829a9b579f3SBram Moolenaar }
2830a9b579f3SBram Moolenaar
2831a9b579f3SBram Moolenaar did_emsg |= save_did_emsg;
28320ba48e8cSBram Moolenaar funcdepth_decrement();
2833b47bed2fSBram Moolenaar for (i = 0; i < tv_to_free_len; ++i)
2834b47bed2fSBram Moolenaar clear_tv(tv_to_free[i]);
28356914c64eSBram Moolenaar cleanup_function_call(fc);
2836a9b579f3SBram Moolenaar }
2837a9b579f3SBram Moolenaar
2838a9b579f3SBram Moolenaar /*
28395082471fSBram Moolenaar * Check the argument count for user function "fp".
28405082471fSBram Moolenaar * Return FCERR_UNKNOWN if OK, FCERR_TOOFEW or FCERR_TOOMANY otherwise.
28415082471fSBram Moolenaar */
28425082471fSBram Moolenaar int
check_user_func_argcount(ufunc_T * fp,int argcount)28435082471fSBram Moolenaar check_user_func_argcount(ufunc_T *fp, int argcount)
28445082471fSBram Moolenaar {
28455082471fSBram Moolenaar int regular_args = fp->uf_args.ga_len;
28465082471fSBram Moolenaar
28475082471fSBram Moolenaar if (argcount < regular_args - fp->uf_def_args.ga_len)
28485082471fSBram Moolenaar return FCERR_TOOFEW;
28495082471fSBram Moolenaar else if (!has_varargs(fp) && argcount > regular_args)
28505082471fSBram Moolenaar return FCERR_TOOMANY;
28515082471fSBram Moolenaar return FCERR_UNKNOWN;
28525082471fSBram Moolenaar }
28535082471fSBram Moolenaar
28545082471fSBram Moolenaar /*
28558a7d6542SBram Moolenaar * Call a user function after checking the arguments.
28561e96d9bfSBram Moolenaar */
28578a7d6542SBram Moolenaar int
call_user_func_check(ufunc_T * fp,int argcount,typval_T * argvars,typval_T * rettv,funcexe_T * funcexe,dict_T * selfdict)28588a7d6542SBram Moolenaar call_user_func_check(
28598a7d6542SBram Moolenaar ufunc_T *fp,
28608a7d6542SBram Moolenaar int argcount,
28618a7d6542SBram Moolenaar typval_T *argvars,
28628a7d6542SBram Moolenaar typval_T *rettv,
28638a7d6542SBram Moolenaar funcexe_T *funcexe,
28648a7d6542SBram Moolenaar dict_T *selfdict)
28651e96d9bfSBram Moolenaar {
28668a7d6542SBram Moolenaar int error;
28671e96d9bfSBram Moolenaar
28688a7d6542SBram Moolenaar if (fp->uf_flags & FC_RANGE && funcexe->doesrange != NULL)
28698a7d6542SBram Moolenaar *funcexe->doesrange = TRUE;
28705082471fSBram Moolenaar error = check_user_func_argcount(fp, argcount);
28715082471fSBram Moolenaar if (error != FCERR_UNKNOWN)
28725082471fSBram Moolenaar return error;
28735082471fSBram Moolenaar if ((fp->uf_flags & FC_DICT) && selfdict == NULL)
28748a7d6542SBram Moolenaar error = FCERR_DICT;
28758a7d6542SBram Moolenaar else
28761e96d9bfSBram Moolenaar {
28778a7d6542SBram Moolenaar int did_save_redo = FALSE;
28788a7d6542SBram Moolenaar save_redo_T save_redo;
28791e96d9bfSBram Moolenaar
28801e96d9bfSBram Moolenaar /*
28818a7d6542SBram Moolenaar * Call the user function.
28828a7d6542SBram Moolenaar * Save and restore search patterns, script variables and
28838a7d6542SBram Moolenaar * redo buffer.
2884437bafe4SBram Moolenaar */
28858a7d6542SBram Moolenaar save_search_patterns();
28868a7d6542SBram Moolenaar if (!ins_compl_active())
2887437bafe4SBram Moolenaar {
28888a7d6542SBram Moolenaar saveRedobuff(&save_redo);
28898a7d6542SBram Moolenaar did_save_redo = TRUE;
28908dd3a43dSBram Moolenaar }
28918a7d6542SBram Moolenaar ++fp->uf_calls;
28926f5b6dfbSBram Moolenaar call_user_func(fp, argcount, argvars, rettv, funcexe,
28938a7d6542SBram Moolenaar (fp->uf_flags & FC_DICT) ? selfdict : NULL);
28948a7d6542SBram Moolenaar if (--fp->uf_calls <= 0 && fp->uf_refcount <= 0)
28958a7d6542SBram Moolenaar // Function was unreferenced while being used, free it now.
28968a7d6542SBram Moolenaar func_clear_free(fp, FALSE);
28978a7d6542SBram Moolenaar if (did_save_redo)
28988a7d6542SBram Moolenaar restoreRedobuff(&save_redo);
28998a7d6542SBram Moolenaar restore_search_patterns();
29008a7d6542SBram Moolenaar error = FCERR_NONE;
2901437bafe4SBram Moolenaar }
29028a7d6542SBram Moolenaar return error;
290303ff9bcbSBram Moolenaar }
290403ff9bcbSBram Moolenaar
290527e80c88SBram Moolenaar static funccal_entry_T *funccal_stack = NULL;
290627e80c88SBram Moolenaar
290727e80c88SBram Moolenaar /*
290827e80c88SBram Moolenaar * Save the current function call pointer, and set it to NULL.
290927e80c88SBram Moolenaar * Used when executing autocommands and for ":source".
291027e80c88SBram Moolenaar */
291127e80c88SBram Moolenaar void
save_funccal(funccal_entry_T * entry)291227e80c88SBram Moolenaar save_funccal(funccal_entry_T *entry)
291327e80c88SBram Moolenaar {
291427e80c88SBram Moolenaar entry->top_funccal = current_funccal;
291527e80c88SBram Moolenaar entry->next = funccal_stack;
291627e80c88SBram Moolenaar funccal_stack = entry;
291727e80c88SBram Moolenaar current_funccal = NULL;
291827e80c88SBram Moolenaar }
291927e80c88SBram Moolenaar
292027e80c88SBram Moolenaar void
restore_funccal(void)292127e80c88SBram Moolenaar restore_funccal(void)
292227e80c88SBram Moolenaar {
292327e80c88SBram Moolenaar if (funccal_stack == NULL)
2924f9e3e09fSBram Moolenaar iemsg("INTERNAL: restore_funccal()");
292527e80c88SBram Moolenaar else
292627e80c88SBram Moolenaar {
292727e80c88SBram Moolenaar current_funccal = funccal_stack->top_funccal;
292827e80c88SBram Moolenaar funccal_stack = funccal_stack->next;
292927e80c88SBram Moolenaar }
293027e80c88SBram Moolenaar }
293127e80c88SBram Moolenaar
2932fa55cfc6SBram Moolenaar funccall_T *
get_current_funccal(void)2933fa55cfc6SBram Moolenaar get_current_funccal(void)
2934fa55cfc6SBram Moolenaar {
2935fa55cfc6SBram Moolenaar return current_funccal;
2936fa55cfc6SBram Moolenaar }
2937fa55cfc6SBram Moolenaar
29384c17ad94SBram Moolenaar /*
29394c17ad94SBram Moolenaar * Mark all functions of script "sid" as deleted.
29404c17ad94SBram Moolenaar */
29414c17ad94SBram Moolenaar void
delete_script_functions(int sid)29424c17ad94SBram Moolenaar delete_script_functions(int sid)
29434c17ad94SBram Moolenaar {
29444c17ad94SBram Moolenaar hashitem_T *hi;
29454c17ad94SBram Moolenaar ufunc_T *fp;
2946ce658356SBram Moolenaar long_u todo = 1;
2947909ed7e9SBram Moolenaar char_u buf[30];
29484c17ad94SBram Moolenaar size_t len;
29494c17ad94SBram Moolenaar
29504c17ad94SBram Moolenaar buf[0] = K_SPECIAL;
29514c17ad94SBram Moolenaar buf[1] = KS_EXTRA;
29524c17ad94SBram Moolenaar buf[2] = (int)KE_SNR;
2953909ed7e9SBram Moolenaar sprintf((char *)buf + 3, "%d_", sid);
29544c17ad94SBram Moolenaar len = STRLEN(buf);
29554c17ad94SBram Moolenaar
2956ce658356SBram Moolenaar while (todo > 0)
2957ce658356SBram Moolenaar {
29584c17ad94SBram Moolenaar todo = func_hashtab.ht_used;
29594c17ad94SBram Moolenaar for (hi = func_hashtab.ht_array; todo > 0; ++hi)
29604c17ad94SBram Moolenaar if (!HASHITEM_EMPTY(hi))
29614c17ad94SBram Moolenaar {
296203afdcf1SBram Moolenaar fp = HI2UF(hi);
29634c17ad94SBram Moolenaar if (STRNCMP(fp->uf_name, buf, len) == 0)
29644c17ad94SBram Moolenaar {
2965ce658356SBram Moolenaar int changed = func_hashtab.ht_changed;
2966ce658356SBram Moolenaar
29674c17ad94SBram Moolenaar fp->uf_flags |= FC_DEAD;
2968c970e422SBram Moolenaar
2969c970e422SBram Moolenaar if (fp->uf_calls > 0)
2970c970e422SBram Moolenaar {
2971c970e422SBram Moolenaar // Function is executing, don't free it but do remove
2972c970e422SBram Moolenaar // it from the hashtable.
2973c970e422SBram Moolenaar if (func_remove(fp))
2974c970e422SBram Moolenaar fp->uf_refcount--;
2975c970e422SBram Moolenaar }
2976c970e422SBram Moolenaar else
2977c970e422SBram Moolenaar {
29784c17ad94SBram Moolenaar func_clear(fp, TRUE);
2979c970e422SBram Moolenaar // When clearing a function another function can be
2980c970e422SBram Moolenaar // cleared as a side effect. When that happens start
2981c970e422SBram Moolenaar // over.
2982ce658356SBram Moolenaar if (changed != func_hashtab.ht_changed)
2983ce658356SBram Moolenaar break;
29844c17ad94SBram Moolenaar }
2985c970e422SBram Moolenaar }
29864c17ad94SBram Moolenaar --todo;
29874c17ad94SBram Moolenaar }
29884c17ad94SBram Moolenaar }
2989ce658356SBram Moolenaar }
29904c17ad94SBram Moolenaar
2991a9b579f3SBram Moolenaar #if defined(EXITFREE) || defined(PROTO)
2992a9b579f3SBram Moolenaar void
free_all_functions(void)2993a9b579f3SBram Moolenaar free_all_functions(void)
2994a9b579f3SBram Moolenaar {
2995a9b579f3SBram Moolenaar hashitem_T *hi;
2996c2574870SBram Moolenaar ufunc_T *fp;
2997c2574870SBram Moolenaar long_u skipped = 0;
299803ff9bcbSBram Moolenaar long_u todo = 1;
29991f22cc5cSBram Moolenaar int changed;
3000a9b579f3SBram Moolenaar
3001e38eab22SBram Moolenaar // Clean up the current_funccal chain and the funccal stack.
30026914c64eSBram Moolenaar while (current_funccal != NULL)
30036914c64eSBram Moolenaar {
30046914c64eSBram Moolenaar clear_tv(current_funccal->rettv);
30056914c64eSBram Moolenaar cleanup_function_call(current_funccal);
300627e80c88SBram Moolenaar if (current_funccal == NULL && funccal_stack != NULL)
300727e80c88SBram Moolenaar restore_funccal();
30086914c64eSBram Moolenaar }
30096914c64eSBram Moolenaar
3010e38eab22SBram Moolenaar // First clear what the functions contain. Since this may lower the
3011e38eab22SBram Moolenaar // reference count of a function, it may also free a function and change
3012e38eab22SBram Moolenaar // the hash table. Restart if that happens.
301303ff9bcbSBram Moolenaar while (todo > 0)
301403ff9bcbSBram Moolenaar {
301503ff9bcbSBram Moolenaar todo = func_hashtab.ht_used;
301603ff9bcbSBram Moolenaar for (hi = func_hashtab.ht_array; todo > 0; ++hi)
301703ff9bcbSBram Moolenaar if (!HASHITEM_EMPTY(hi))
301803ff9bcbSBram Moolenaar {
30198a7d6542SBram Moolenaar // clear the def function index now
30208a7d6542SBram Moolenaar fp = HI2UF(hi);
30218a7d6542SBram Moolenaar fp->uf_flags &= ~FC_DEAD;
30220cb5bcf5SBram Moolenaar fp->uf_def_status = UF_NOT_COMPILED;
30238a7d6542SBram Moolenaar
3024e38eab22SBram Moolenaar // Only free functions that are not refcounted, those are
3025e38eab22SBram Moolenaar // supposed to be freed when no longer referenced.
302603ff9bcbSBram Moolenaar if (func_name_refcount(fp->uf_name))
302703ff9bcbSBram Moolenaar ++skipped;
302803ff9bcbSBram Moolenaar else
302903ff9bcbSBram Moolenaar {
30301f22cc5cSBram Moolenaar changed = func_hashtab.ht_changed;
303103ff9bcbSBram Moolenaar func_clear(fp, TRUE);
30321f22cc5cSBram Moolenaar if (changed != func_hashtab.ht_changed)
303303ff9bcbSBram Moolenaar {
303403ff9bcbSBram Moolenaar skipped = 0;
303503ff9bcbSBram Moolenaar break;
303603ff9bcbSBram Moolenaar }
303703ff9bcbSBram Moolenaar }
303803ff9bcbSBram Moolenaar --todo;
303903ff9bcbSBram Moolenaar }
304003ff9bcbSBram Moolenaar }
304103ff9bcbSBram Moolenaar
3042e38eab22SBram Moolenaar // Now actually free the functions. Need to start all over every time,
3043e38eab22SBram Moolenaar // because func_free() may change the hash table.
304403ff9bcbSBram Moolenaar skipped = 0;
3045c2574870SBram Moolenaar while (func_hashtab.ht_used > skipped)
3046c2574870SBram Moolenaar {
3047c2574870SBram Moolenaar todo = func_hashtab.ht_used;
3048c2574870SBram Moolenaar for (hi = func_hashtab.ht_array; todo > 0; ++hi)
3049a9b579f3SBram Moolenaar if (!HASHITEM_EMPTY(hi))
3050a9b579f3SBram Moolenaar {
3051c2574870SBram Moolenaar --todo;
3052e38eab22SBram Moolenaar // Only free functions that are not refcounted, those are
3053e38eab22SBram Moolenaar // supposed to be freed when no longer referenced.
3054c2574870SBram Moolenaar fp = HI2UF(hi);
3055c2574870SBram Moolenaar if (func_name_refcount(fp->uf_name))
3056c2574870SBram Moolenaar ++skipped;
3057c2574870SBram Moolenaar else
3058c2574870SBram Moolenaar {
3059a05e524fSBram Moolenaar if (func_free(fp, FALSE) == OK)
3060a05e524fSBram Moolenaar {
3061c2574870SBram Moolenaar skipped = 0;
3062a9b579f3SBram Moolenaar break;
3063a9b579f3SBram Moolenaar }
3064a05e524fSBram Moolenaar // did not actually free it
3065a05e524fSBram Moolenaar ++skipped;
3066a05e524fSBram Moolenaar }
3067c2574870SBram Moolenaar }
3068c2574870SBram Moolenaar }
3069c2574870SBram Moolenaar if (skipped == 0)
3070a9b579f3SBram Moolenaar hash_clear(&func_hashtab);
30718a7d6542SBram Moolenaar
30728a7d6542SBram Moolenaar free_def_functions();
3073a9b579f3SBram Moolenaar }
3074a9b579f3SBram Moolenaar #endif
3075a9b579f3SBram Moolenaar
3076a9b579f3SBram Moolenaar /*
3077a9b579f3SBram Moolenaar * Return TRUE if "name" looks like a builtin function name: starts with a
3078a26b9700SBram Moolenaar * lower case letter and doesn't contain AUTOLOAD_CHAR or ':'.
3079a9b579f3SBram Moolenaar * "len" is the length of "name", or -1 for NUL terminated.
3080a9b579f3SBram Moolenaar */
30818a7d6542SBram Moolenaar int
builtin_function(char_u * name,int len)3082a9b579f3SBram Moolenaar builtin_function(char_u *name, int len)
3083a9b579f3SBram Moolenaar {
3084a9b579f3SBram Moolenaar char_u *p;
3085a9b579f3SBram Moolenaar
3086a26b9700SBram Moolenaar if (!ASCII_ISLOWER(name[0]) || name[1] == ':')
3087a9b579f3SBram Moolenaar return FALSE;
3088a9b579f3SBram Moolenaar p = vim_strchr(name, AUTOLOAD_CHAR);
3089a9b579f3SBram Moolenaar return p == NULL || (len > 0 && p > name + len);
3090a9b579f3SBram Moolenaar }
3091a9b579f3SBram Moolenaar
3092a9b579f3SBram Moolenaar int
func_call(char_u * name,typval_T * args,partial_T * partial,dict_T * selfdict,typval_T * rettv)3093a9b579f3SBram Moolenaar func_call(
3094a9b579f3SBram Moolenaar char_u *name,
3095a9b579f3SBram Moolenaar typval_T *args,
3096a9b579f3SBram Moolenaar partial_T *partial,
3097a9b579f3SBram Moolenaar dict_T *selfdict,
3098a9b579f3SBram Moolenaar typval_T *rettv)
3099a9b579f3SBram Moolenaar {
310050985eb1SBram Moolenaar list_T *l = args->vval.v_list;
3101a9b579f3SBram Moolenaar listitem_T *item;
3102a9b579f3SBram Moolenaar typval_T argv[MAX_FUNC_ARGS + 1];
3103a9b579f3SBram Moolenaar int argc = 0;
3104a9b579f3SBram Moolenaar int r = 0;
3105a9b579f3SBram Moolenaar
31067e9f351bSBram Moolenaar CHECK_LIST_MATERIALIZE(l);
310700d253e2SBram Moolenaar FOR_ALL_LIST_ITEMS(l, item)
3108a9b579f3SBram Moolenaar {
3109a9b579f3SBram Moolenaar if (argc == MAX_FUNC_ARGS - (partial == NULL ? 0 : partial->pt_argc))
3110a9b579f3SBram Moolenaar {
3111f9e3e09fSBram Moolenaar emsg(_("E699: Too many arguments"));
3112a9b579f3SBram Moolenaar break;
3113a9b579f3SBram Moolenaar }
3114e38eab22SBram Moolenaar // Make a copy of each argument. This is needed to be able to set
3115e38eab22SBram Moolenaar // v_lock to VAR_FIXED in the copy without changing the original list.
3116a9b579f3SBram Moolenaar copy_tv(&item->li_tv, &argv[argc++]);
3117a9b579f3SBram Moolenaar }
3118a9b579f3SBram Moolenaar
3119a9b579f3SBram Moolenaar if (item == NULL)
3120c6538bccSBram Moolenaar {
3121c6538bccSBram Moolenaar funcexe_T funcexe;
3122c6538bccSBram Moolenaar
3123a80faa89SBram Moolenaar CLEAR_FIELD(funcexe);
3124c6538bccSBram Moolenaar funcexe.firstline = curwin->w_cursor.lnum;
3125c6538bccSBram Moolenaar funcexe.lastline = curwin->w_cursor.lnum;
3126c6538bccSBram Moolenaar funcexe.evaluate = TRUE;
3127c6538bccSBram Moolenaar funcexe.partial = partial;
3128c6538bccSBram Moolenaar funcexe.selfdict = selfdict;
3129c6538bccSBram Moolenaar r = call_func(name, -1, rettv, argc, argv, &funcexe);
3130c6538bccSBram Moolenaar }
3131a9b579f3SBram Moolenaar
3132e38eab22SBram Moolenaar // Free the arguments.
3133a9b579f3SBram Moolenaar while (argc > 0)
3134a9b579f3SBram Moolenaar clear_tv(&argv[--argc]);
3135a9b579f3SBram Moolenaar
3136a9b579f3SBram Moolenaar return r;
3137a9b579f3SBram Moolenaar }
3138a9b579f3SBram Moolenaar
31390e57dd85SBram Moolenaar static int callback_depth = 0;
31400e57dd85SBram Moolenaar
31410e57dd85SBram Moolenaar int
get_callback_depth(void)31420e57dd85SBram Moolenaar get_callback_depth(void)
31430e57dd85SBram Moolenaar {
31440e57dd85SBram Moolenaar return callback_depth;
31450e57dd85SBram Moolenaar }
31460e57dd85SBram Moolenaar
3147a9b579f3SBram Moolenaar /*
31483a97bb3fSBram Moolenaar * Invoke call_func() with a callback.
31493a97bb3fSBram Moolenaar */
31503a97bb3fSBram Moolenaar int
call_callback(callback_T * callback,int len,typval_T * rettv,int argcount,typval_T * argvars)31513a97bb3fSBram Moolenaar call_callback(
31523a97bb3fSBram Moolenaar callback_T *callback,
31533a97bb3fSBram Moolenaar int len, // length of "name" or -1 to use strlen()
31543a97bb3fSBram Moolenaar typval_T *rettv, // return value goes here
31553a97bb3fSBram Moolenaar int argcount, // number of "argvars"
3156c6538bccSBram Moolenaar typval_T *argvars) // vars for arguments, must have "argcount"
31573a97bb3fSBram Moolenaar // PLUS ONE elements!
31583a97bb3fSBram Moolenaar {
3159c6538bccSBram Moolenaar funcexe_T funcexe;
31600e57dd85SBram Moolenaar int ret;
3161c6538bccSBram Moolenaar
3162a80faa89SBram Moolenaar CLEAR_FIELD(funcexe);
3163c6538bccSBram Moolenaar funcexe.evaluate = TRUE;
3164c6538bccSBram Moolenaar funcexe.partial = callback->cb_partial;
31650e57dd85SBram Moolenaar ++callback_depth;
31660e57dd85SBram Moolenaar ret = call_func(callback->cb_name, len, rettv, argcount, argvars, &funcexe);
31670e57dd85SBram Moolenaar --callback_depth;
31680e57dd85SBram Moolenaar return ret;
31693a97bb3fSBram Moolenaar }
31703a97bb3fSBram Moolenaar
31713a97bb3fSBram Moolenaar /*
31728a7d6542SBram Moolenaar * Give an error message for the result of a function.
31738a7d6542SBram Moolenaar * Nothing if "error" is FCERR_NONE.
31748a7d6542SBram Moolenaar */
31758a7d6542SBram Moolenaar void
user_func_error(int error,char_u * name)31768a7d6542SBram Moolenaar user_func_error(int error, char_u *name)
31778a7d6542SBram Moolenaar {
31788a7d6542SBram Moolenaar switch (error)
31798a7d6542SBram Moolenaar {
31808a7d6542SBram Moolenaar case FCERR_UNKNOWN:
31818a7d6542SBram Moolenaar emsg_funcname(e_unknownfunc, name);
31828a7d6542SBram Moolenaar break;
31838a7d6542SBram Moolenaar case FCERR_NOTMETHOD:
31848a7d6542SBram Moolenaar emsg_funcname(
31858a7d6542SBram Moolenaar N_("E276: Cannot use function as a method: %s"), name);
31868a7d6542SBram Moolenaar break;
31878a7d6542SBram Moolenaar case FCERR_DELETED:
31888a7d6542SBram Moolenaar emsg_funcname(N_(e_func_deleted), name);
31898a7d6542SBram Moolenaar break;
31908a7d6542SBram Moolenaar case FCERR_TOOMANY:
31918a7d6542SBram Moolenaar emsg_funcname((char *)e_toomanyarg, name);
31928a7d6542SBram Moolenaar break;
31938a7d6542SBram Moolenaar case FCERR_TOOFEW:
31948a7d6542SBram Moolenaar emsg_funcname((char *)e_toofewarg, name);
31958a7d6542SBram Moolenaar break;
31968a7d6542SBram Moolenaar case FCERR_SCRIPT:
31978a7d6542SBram Moolenaar emsg_funcname(
31988a7d6542SBram Moolenaar N_("E120: Using <SID> not in a script context: %s"), name);
31998a7d6542SBram Moolenaar break;
32008a7d6542SBram Moolenaar case FCERR_DICT:
32018a7d6542SBram Moolenaar emsg_funcname(
32028a7d6542SBram Moolenaar N_("E725: Calling dict function without Dictionary: %s"),
32038a7d6542SBram Moolenaar name);
32048a7d6542SBram Moolenaar break;
32058a7d6542SBram Moolenaar }
32068a7d6542SBram Moolenaar }
32078a7d6542SBram Moolenaar
32088a7d6542SBram Moolenaar /*
3209a9b579f3SBram Moolenaar * Call a function with its resolved parameters
3210df48fb45SBram Moolenaar *
3211a9b579f3SBram Moolenaar * Return FAIL when the function can't be called, OK otherwise.
3212a9b579f3SBram Moolenaar * Also returns OK when an error was encountered while executing the function.
3213a9b579f3SBram Moolenaar */
3214a9b579f3SBram Moolenaar int
call_func(char_u * funcname,int len,typval_T * rettv,int argcount_in,typval_T * argvars_in,funcexe_T * funcexe)3215a9b579f3SBram Moolenaar call_func(
32166ed88198SBram Moolenaar char_u *funcname, // name of the function
32176ed88198SBram Moolenaar int len, // length of "name" or -1 to use strlen()
32186ed88198SBram Moolenaar typval_T *rettv, // return value goes here
32196ed88198SBram Moolenaar int argcount_in, // number of "argvars"
32206ed88198SBram Moolenaar typval_T *argvars_in, // vars for arguments, must have "argcount"
32216ed88198SBram Moolenaar // PLUS ONE elements!
3222c6538bccSBram Moolenaar funcexe_T *funcexe) // more arguments
3223a9b579f3SBram Moolenaar {
3224a9b579f3SBram Moolenaar int ret = FAIL;
3225ef140544SBram Moolenaar int error = FCERR_NONE;
3226a9b579f3SBram Moolenaar int i;
3227f10806b2SBram Moolenaar ufunc_T *fp = NULL;
3228a9b579f3SBram Moolenaar char_u fname_buf[FLEN_FIXED + 1];
3229a9b579f3SBram Moolenaar char_u *tofree = NULL;
3230f10806b2SBram Moolenaar char_u *fname = NULL;
3231f10806b2SBram Moolenaar char_u *name = NULL;
3232a9b579f3SBram Moolenaar int argcount = argcount_in;
3233a9b579f3SBram Moolenaar typval_T *argvars = argvars_in;
3234c6538bccSBram Moolenaar dict_T *selfdict = funcexe->selfdict;
3235fcfe1a9bSBram Moolenaar typval_T argv[MAX_FUNC_ARGS + 1]; // used when "partial" or
3236fcfe1a9bSBram Moolenaar // "funcexe->basetv" is not NULL
3237a9b579f3SBram Moolenaar int argv_clear = 0;
3238761fdf01SBram Moolenaar int argv_base = 0;
3239c6538bccSBram Moolenaar partial_T *partial = funcexe->partial;
324097f227d9SBram Moolenaar type_T check_type;
3241a9b579f3SBram Moolenaar
3242c507a2d1SBram Moolenaar // Initialize rettv so that it is safe for caller to invoke clear_tv(rettv)
3243c507a2d1SBram Moolenaar // even when call_func() returns FAIL.
3244c507a2d1SBram Moolenaar rettv->v_type = VAR_UNKNOWN;
3245c507a2d1SBram Moolenaar
3246f10806b2SBram Moolenaar if (partial != NULL)
3247f10806b2SBram Moolenaar fp = partial->pt_func;
3248f10806b2SBram Moolenaar if (fp == NULL)
3249f10806b2SBram Moolenaar {
3250f10806b2SBram Moolenaar // Make a copy of the name, if it comes from a funcref variable it
3251f10806b2SBram Moolenaar // could be changed or deleted in the called function.
32526ed88198SBram Moolenaar name = len > 0 ? vim_strnsave(funcname, len) : vim_strsave(funcname);
3253a9b579f3SBram Moolenaar if (name == NULL)
3254a9b579f3SBram Moolenaar return ret;
3255a9b579f3SBram Moolenaar
3256a9b579f3SBram Moolenaar fname = fname_trans_sid(name, fname_buf, &tofree, &error);
3257f10806b2SBram Moolenaar }
3258a9b579f3SBram Moolenaar
3259c6538bccSBram Moolenaar if (funcexe->doesrange != NULL)
3260c6538bccSBram Moolenaar *funcexe->doesrange = FALSE;
3261a9b579f3SBram Moolenaar
3262a9b579f3SBram Moolenaar if (partial != NULL)
3263a9b579f3SBram Moolenaar {
3264e38eab22SBram Moolenaar // When the function has a partial with a dict and there is a dict
3265e38eab22SBram Moolenaar // argument, use the dict argument. That is backwards compatible.
3266e38eab22SBram Moolenaar // When the dict was bound explicitly use the one from the partial.
3267c6538bccSBram Moolenaar if (partial->pt_dict != NULL && (selfdict == NULL || !partial->pt_auto))
3268a9b579f3SBram Moolenaar selfdict = partial->pt_dict;
3269ef140544SBram Moolenaar if (error == FCERR_NONE && partial->pt_argc > 0)
3270a9b579f3SBram Moolenaar {
3271a9b579f3SBram Moolenaar for (argv_clear = 0; argv_clear < partial->pt_argc; ++argv_clear)
32724c054e9fSBram Moolenaar {
32734c054e9fSBram Moolenaar if (argv_clear + argcount_in >= MAX_FUNC_ARGS)
32744c054e9fSBram Moolenaar {
3275ef140544SBram Moolenaar error = FCERR_TOOMANY;
32764c054e9fSBram Moolenaar goto theend;
32774c054e9fSBram Moolenaar }
3278a9b579f3SBram Moolenaar copy_tv(&partial->pt_argv[argv_clear], &argv[argv_clear]);
32794c054e9fSBram Moolenaar }
3280a9b579f3SBram Moolenaar for (i = 0; i < argcount_in; ++i)
3281a9b579f3SBram Moolenaar argv[i + argv_clear] = argvars_in[i];
3282a9b579f3SBram Moolenaar argvars = argv;
3283a9b579f3SBram Moolenaar argcount = partial->pt_argc + argcount_in;
328497f227d9SBram Moolenaar
328522f85d04SBram Moolenaar if (funcexe->check_type != NULL
328622f85d04SBram Moolenaar && funcexe->check_type->tt_argcount != -1)
328797f227d9SBram Moolenaar {
328897f227d9SBram Moolenaar // Now funcexe->check_type is missing the added arguments, make
328997f227d9SBram Moolenaar // a copy of the type with the correction.
329097f227d9SBram Moolenaar check_type = *funcexe->check_type;
329197f227d9SBram Moolenaar funcexe->check_type = &check_type;
329297f227d9SBram Moolenaar check_type.tt_argcount += partial->pt_argc;
329397f227d9SBram Moolenaar check_type.tt_min_argcount += partial->pt_argc;
329497f227d9SBram Moolenaar }
3295a9b579f3SBram Moolenaar }
3296a9b579f3SBram Moolenaar }
3297a9b579f3SBram Moolenaar
329832b3f820SBram Moolenaar if (error == FCERR_NONE && funcexe->check_type != NULL && funcexe->evaluate)
329932b3f820SBram Moolenaar {
330032b3f820SBram Moolenaar // Check that the argument types are OK for the types of the funcref.
330132b3f820SBram Moolenaar if (check_argument_types(funcexe->check_type, argvars, argcount,
33027a6eaa06SBram Moolenaar (name != NULL) ? name : funcname) == FAIL)
330332b3f820SBram Moolenaar error = FCERR_OTHER;
330432b3f820SBram Moolenaar }
330532b3f820SBram Moolenaar
3306ef140544SBram Moolenaar if (error == FCERR_NONE && funcexe->evaluate)
3307a9b579f3SBram Moolenaar {
3308a9b579f3SBram Moolenaar char_u *rfname = fname;
3309333894b1SBram Moolenaar int is_global = FALSE;
3310a9b579f3SBram Moolenaar
3311333894b1SBram Moolenaar // Skip "g:" before a function name.
3312f10806b2SBram Moolenaar if (fp == NULL && fname[0] == 'g' && fname[1] == ':')
3313333894b1SBram Moolenaar {
3314333894b1SBram Moolenaar is_global = TRUE;
3315a9b579f3SBram Moolenaar rfname = fname + 2;
3316333894b1SBram Moolenaar }
3317a9b579f3SBram Moolenaar
3318e38eab22SBram Moolenaar rettv->v_type = VAR_NUMBER; // default rettv is number zero
3319a9b579f3SBram Moolenaar rettv->vval.v_number = 0;
3320ef140544SBram Moolenaar error = FCERR_UNKNOWN;
3321a9b579f3SBram Moolenaar
3322f10806b2SBram Moolenaar if (fp != NULL || !builtin_function(rfname, -1))
3323a9b579f3SBram Moolenaar {
3324a9b579f3SBram Moolenaar /*
3325a9b579f3SBram Moolenaar * User defined function.
3326a9b579f3SBram Moolenaar */
3327f10806b2SBram Moolenaar if (fp == NULL)
3328333894b1SBram Moolenaar fp = find_func(rfname, is_global, NULL);
3329a9b579f3SBram Moolenaar
3330e38eab22SBram Moolenaar // Trigger FuncUndefined event, may load the function.
3331a9b579f3SBram Moolenaar if (fp == NULL
3332a9b579f3SBram Moolenaar && apply_autocmds(EVENT_FUNCUNDEFINED,
3333a9b579f3SBram Moolenaar rfname, rfname, TRUE, NULL)
3334a9b579f3SBram Moolenaar && !aborting())
3335a9b579f3SBram Moolenaar {
3336e38eab22SBram Moolenaar // executed an autocommand, search for the function again
3337333894b1SBram Moolenaar fp = find_func(rfname, is_global, NULL);
3338a9b579f3SBram Moolenaar }
3339e38eab22SBram Moolenaar // Try loading a package.
3340a9b579f3SBram Moolenaar if (fp == NULL && script_autoload(rfname, TRUE) && !aborting())
3341a9b579f3SBram Moolenaar {
3342e38eab22SBram Moolenaar // loaded a package, search for the function again
3343333894b1SBram Moolenaar fp = find_func(rfname, is_global, NULL);
3344a9b579f3SBram Moolenaar }
3345a26b9700SBram Moolenaar if (fp == NULL)
3346a26b9700SBram Moolenaar {
3347a26b9700SBram Moolenaar char_u *p = untrans_function_name(rfname);
3348a26b9700SBram Moolenaar
3349a26b9700SBram Moolenaar // If using Vim9 script try not local to the script.
3350035d6e91SBram Moolenaar // Don't do this if the name starts with "s:".
3351035d6e91SBram Moolenaar if (p != NULL && (funcname[0] != 's' || funcname[1] != ':'))
3352333894b1SBram Moolenaar fp = find_func(p, is_global, NULL);
3353a26b9700SBram Moolenaar }
3354a9b579f3SBram Moolenaar
3355437bafe4SBram Moolenaar if (fp != NULL && (fp->uf_flags & FC_DELETED))
3356ef140544SBram Moolenaar error = FCERR_DELETED;
3357801ab069SBram Moolenaar #ifdef FEAT_LUA
3358801ab069SBram Moolenaar else if (fp != NULL && (fp->uf_flags & FC_CFUNC))
3359801ab069SBram Moolenaar {
3360801ab069SBram Moolenaar cfunc_T cb = fp->uf_cb;
3361801ab069SBram Moolenaar
3362801ab069SBram Moolenaar error = (*cb)(argcount, argvars, rettv, fp->uf_cb_state);
3363801ab069SBram Moolenaar }
3364801ab069SBram Moolenaar #endif
3365437bafe4SBram Moolenaar else if (fp != NULL)
3366a9b579f3SBram Moolenaar {
3367c6538bccSBram Moolenaar if (funcexe->argv_func != NULL)
3368b0745b22SBram Moolenaar // postponed filling in the arguments, do it now
3369b0745b22SBram Moolenaar argcount = funcexe->argv_func(argcount, argvars, argv_clear,
3370c6538bccSBram Moolenaar fp->uf_args.ga_len);
3371df48fb45SBram Moolenaar
3372fcfe1a9bSBram Moolenaar if (funcexe->basetv != NULL)
3373fcfe1a9bSBram Moolenaar {
3374fcfe1a9bSBram Moolenaar // Method call: base->Method()
3375fcfe1a9bSBram Moolenaar mch_memmove(&argv[1], argvars, sizeof(typval_T) * argcount);
3376fcfe1a9bSBram Moolenaar argv[0] = *funcexe->basetv;
3377fcfe1a9bSBram Moolenaar argcount++;
3378761fdf01SBram Moolenaar argvars = argv;
3379761fdf01SBram Moolenaar argv_base = 1;
3380fcfe1a9bSBram Moolenaar }
3381fcfe1a9bSBram Moolenaar
33828a7d6542SBram Moolenaar error = call_user_func_check(fp, argcount, argvars, rettv,
33838a7d6542SBram Moolenaar funcexe, selfdict);
3384a9b579f3SBram Moolenaar }
3385a9b579f3SBram Moolenaar }
3386ac92e25aSBram Moolenaar else if (funcexe->basetv != NULL)
3387ac92e25aSBram Moolenaar {
3388ac92e25aSBram Moolenaar /*
3389fcfe1a9bSBram Moolenaar * expr->method(): Find the method name in the table, call its
3390fcfe1a9bSBram Moolenaar * implementation with the base as one of the arguments.
3391ac92e25aSBram Moolenaar */
3392ac92e25aSBram Moolenaar error = call_internal_method(fname, argcount, argvars, rettv,
3393ac92e25aSBram Moolenaar funcexe->basetv);
3394ac92e25aSBram Moolenaar }
3395a9b579f3SBram Moolenaar else
3396a9b579f3SBram Moolenaar {
3397a9b579f3SBram Moolenaar /*
3398a9b579f3SBram Moolenaar * Find the function name in the table, call its implementation.
3399a9b579f3SBram Moolenaar */
3400a9b579f3SBram Moolenaar error = call_internal_func(fname, argcount, argvars, rettv);
3401a9b579f3SBram Moolenaar }
3402333894b1SBram Moolenaar
3403a9b579f3SBram Moolenaar /*
3404a9b579f3SBram Moolenaar * The function call (or "FuncUndefined" autocommand sequence) might
3405a9b579f3SBram Moolenaar * have been aborted by an error, an interrupt, or an explicitly thrown
3406a9b579f3SBram Moolenaar * exception that has not been caught so far. This situation can be
3407a9b579f3SBram Moolenaar * tested for by calling aborting(). For an error in an internal
3408a9b579f3SBram Moolenaar * function or for the "E132" error in call_user_func(), however, the
3409a9b579f3SBram Moolenaar * throw point at which the "force_abort" flag (temporarily reset by
3410a9b579f3SBram Moolenaar * emsg()) is normally updated has not been reached yet. We need to
3411a9b579f3SBram Moolenaar * update that flag first to make aborting() reliable.
3412a9b579f3SBram Moolenaar */
3413a9b579f3SBram Moolenaar update_force_abort();
3414a9b579f3SBram Moolenaar }
3415ef140544SBram Moolenaar if (error == FCERR_NONE)
3416a9b579f3SBram Moolenaar ret = OK;
3417a9b579f3SBram Moolenaar
34184c054e9fSBram Moolenaar theend:
3419a9b579f3SBram Moolenaar /*
3420a9b579f3SBram Moolenaar * Report an error unless the argument evaluation or function call has been
3421a9b579f3SBram Moolenaar * cancelled due to an aborting error, an interrupt, or an exception.
3422a9b579f3SBram Moolenaar */
3423a9b579f3SBram Moolenaar if (!aborting())
3424a9b579f3SBram Moolenaar {
3425f10806b2SBram Moolenaar user_func_error(error, (name != NULL) ? name : funcname);
3426a9b579f3SBram Moolenaar }
3427a9b579f3SBram Moolenaar
3428761fdf01SBram Moolenaar // clear the copies made from the partial
3429a9b579f3SBram Moolenaar while (argv_clear > 0)
3430761fdf01SBram Moolenaar clear_tv(&argv[--argv_clear + argv_base]);
3431761fdf01SBram Moolenaar
3432a9b579f3SBram Moolenaar vim_free(tofree);
3433a9b579f3SBram Moolenaar vim_free(name);
3434a9b579f3SBram Moolenaar
3435a9b579f3SBram Moolenaar return ret;
3436a9b579f3SBram Moolenaar }
3437a9b579f3SBram Moolenaar
3438682d0a15SBram Moolenaar char_u *
printable_func_name(ufunc_T * fp)34398a7d6542SBram Moolenaar printable_func_name(ufunc_T *fp)
34408a7d6542SBram Moolenaar {
34418a7d6542SBram Moolenaar return fp->uf_name_exp != NULL ? fp->uf_name_exp : fp->uf_name;
34428a7d6542SBram Moolenaar }
34438a7d6542SBram Moolenaar
3444a9b579f3SBram Moolenaar /*
344561a6d4e4SBram Moolenaar * List the head of the function: "function name(arg1, arg2)".
3446a9b579f3SBram Moolenaar */
3447a9b579f3SBram Moolenaar static void
list_func_head(ufunc_T * fp,int indent)3448a9b579f3SBram Moolenaar list_func_head(ufunc_T *fp, int indent)
3449a9b579f3SBram Moolenaar {
3450a9b579f3SBram Moolenaar int j;
3451a9b579f3SBram Moolenaar
3452a9b579f3SBram Moolenaar msg_start();
3453a9b579f3SBram Moolenaar if (indent)
345432526b3cSBram Moolenaar msg_puts(" ");
34550cb5bcf5SBram Moolenaar if (fp->uf_def_status != UF_NOT_COMPILED)
345661a6d4e4SBram Moolenaar msg_puts("def ");
345761a6d4e4SBram Moolenaar else
345832526b3cSBram Moolenaar msg_puts("function ");
34598a7d6542SBram Moolenaar msg_puts((char *)printable_func_name(fp));
3460a9b579f3SBram Moolenaar msg_putchar('(');
3461a9b579f3SBram Moolenaar for (j = 0; j < fp->uf_args.ga_len; ++j)
3462a9b579f3SBram Moolenaar {
3463a9b579f3SBram Moolenaar if (j)
346432526b3cSBram Moolenaar msg_puts(", ");
346532526b3cSBram Moolenaar msg_puts((char *)FUNCARG(fp, j));
34668a7d6542SBram Moolenaar if (fp->uf_arg_types != NULL)
34678a7d6542SBram Moolenaar {
34688a7d6542SBram Moolenaar char *tofree;
34698a7d6542SBram Moolenaar
34708a7d6542SBram Moolenaar msg_puts(": ");
34718a7d6542SBram Moolenaar msg_puts(type_name(fp->uf_arg_types[j], &tofree));
34728a7d6542SBram Moolenaar vim_free(tofree);
34738a7d6542SBram Moolenaar }
347442ae78cfSBram Moolenaar if (j >= fp->uf_args.ga_len - fp->uf_def_args.ga_len)
347542ae78cfSBram Moolenaar {
347642ae78cfSBram Moolenaar msg_puts(" = ");
347742ae78cfSBram Moolenaar msg_puts(((char **)(fp->uf_def_args.ga_data))
347842ae78cfSBram Moolenaar [j - fp->uf_args.ga_len + fp->uf_def_args.ga_len]);
347942ae78cfSBram Moolenaar }
3480a9b579f3SBram Moolenaar }
3481a9b579f3SBram Moolenaar if (fp->uf_varargs)
3482a9b579f3SBram Moolenaar {
3483a9b579f3SBram Moolenaar if (j)
348432526b3cSBram Moolenaar msg_puts(", ");
348532526b3cSBram Moolenaar msg_puts("...");
3486a9b579f3SBram Moolenaar }
34878a7d6542SBram Moolenaar if (fp->uf_va_name != NULL)
34888a7d6542SBram Moolenaar {
34898a7d6542SBram Moolenaar if (j)
34908a7d6542SBram Moolenaar msg_puts(", ");
34918a7d6542SBram Moolenaar msg_puts("...");
34928a7d6542SBram Moolenaar msg_puts((char *)fp->uf_va_name);
34932a38908bSBram Moolenaar if (fp->uf_va_type != NULL)
34948a7d6542SBram Moolenaar {
34958a7d6542SBram Moolenaar char *tofree;
34968a7d6542SBram Moolenaar
34978a7d6542SBram Moolenaar msg_puts(": ");
34988a7d6542SBram Moolenaar msg_puts(type_name(fp->uf_va_type, &tofree));
34998a7d6542SBram Moolenaar vim_free(tofree);
35008a7d6542SBram Moolenaar }
35018a7d6542SBram Moolenaar }
3502a9b579f3SBram Moolenaar msg_putchar(')');
350361a6d4e4SBram Moolenaar
35040cb5bcf5SBram Moolenaar if (fp->uf_def_status != UF_NOT_COMPILED)
350561a6d4e4SBram Moolenaar {
350661a6d4e4SBram Moolenaar if (fp->uf_ret_type != &t_void)
350761a6d4e4SBram Moolenaar {
350861a6d4e4SBram Moolenaar char *tofree;
350961a6d4e4SBram Moolenaar
351061a6d4e4SBram Moolenaar msg_puts(": ");
351161a6d4e4SBram Moolenaar msg_puts(type_name(fp->uf_ret_type, &tofree));
351261a6d4e4SBram Moolenaar vim_free(tofree);
351361a6d4e4SBram Moolenaar }
351461a6d4e4SBram Moolenaar }
351561a6d4e4SBram Moolenaar else if (fp->uf_flags & FC_ABORT)
351632526b3cSBram Moolenaar msg_puts(" abort");
3517a9b579f3SBram Moolenaar if (fp->uf_flags & FC_RANGE)
351832526b3cSBram Moolenaar msg_puts(" range");
3519a9b579f3SBram Moolenaar if (fp->uf_flags & FC_DICT)
352032526b3cSBram Moolenaar msg_puts(" dict");
352110ce39a0SBram Moolenaar if (fp->uf_flags & FC_CLOSURE)
352232526b3cSBram Moolenaar msg_puts(" closure");
3523a9b579f3SBram Moolenaar msg_clr_eos();
3524a9b579f3SBram Moolenaar if (p_verbose > 0)
3525f29c1c6aSBram Moolenaar last_set_msg(fp->uf_script_ctx);
3526a9b579f3SBram Moolenaar }
3527a9b579f3SBram Moolenaar
3528a9b579f3SBram Moolenaar /*
3529a9b579f3SBram Moolenaar * Get a function name, translating "<SID>" and "<SNR>".
3530a9b579f3SBram Moolenaar * Also handles a Funcref in a List or Dictionary.
3531a9b579f3SBram Moolenaar * Returns the function name in allocated memory, or NULL for failure.
35324c17ad94SBram Moolenaar * Set "*is_global" to TRUE when the function must be global, unless
35334c17ad94SBram Moolenaar * "is_global" is NULL.
3534a9b579f3SBram Moolenaar * flags:
3535a9b579f3SBram Moolenaar * TFN_INT: internal function name OK
3536a9b579f3SBram Moolenaar * TFN_QUIET: be quiet
3537a9b579f3SBram Moolenaar * TFN_NO_AUTOLOAD: do not use script autoloading
3538b54c3ff3SBram Moolenaar * TFN_NO_DEREF: do not dereference a Funcref
3539a9b579f3SBram Moolenaar * Advances "pp" to just after the function name (if no error).
3540a9b579f3SBram Moolenaar */
3541437bafe4SBram Moolenaar char_u *
trans_function_name(char_u ** pp,int * is_global,int skip,int flags,funcdict_T * fdp,partial_T ** partial,type_T ** type)3542a9b579f3SBram Moolenaar trans_function_name(
3543a9b579f3SBram Moolenaar char_u **pp,
35444c17ad94SBram Moolenaar int *is_global,
3545e38eab22SBram Moolenaar int skip, // only find the end, don't evaluate
3546a9b579f3SBram Moolenaar int flags,
3547e38eab22SBram Moolenaar funcdict_T *fdp, // return: info about dictionary used
354832b3f820SBram Moolenaar partial_T **partial, // return: partial of a FuncRef
354932b3f820SBram Moolenaar type_T **type) // return: type of funcref if not NULL
3550a9b579f3SBram Moolenaar {
3551a9b579f3SBram Moolenaar char_u *name = NULL;
3552a9b579f3SBram Moolenaar char_u *start;
3553a9b579f3SBram Moolenaar char_u *end;
3554a9b579f3SBram Moolenaar int lead;
3555a9b579f3SBram Moolenaar char_u sid_buf[20];
3556a9b579f3SBram Moolenaar int len;
35578a7d6542SBram Moolenaar int extra = 0;
3558a9b579f3SBram Moolenaar lval_T lv;
35598a7d6542SBram Moolenaar int vim9script;
35607b5d5442SBram Moolenaar static char *e_function_name = N_("E129: Function name required");
3561a9b579f3SBram Moolenaar
3562a9b579f3SBram Moolenaar if (fdp != NULL)
3563a80faa89SBram Moolenaar CLEAR_POINTER(fdp);
3564a9b579f3SBram Moolenaar start = *pp;
3565a9b579f3SBram Moolenaar
3566e38eab22SBram Moolenaar // Check for hard coded <SNR>: already translated function ID (from a user
3567e38eab22SBram Moolenaar // command).
3568a9b579f3SBram Moolenaar if ((*pp)[0] == K_SPECIAL && (*pp)[1] == KS_EXTRA
3569a9b579f3SBram Moolenaar && (*pp)[2] == (int)KE_SNR)
3570a9b579f3SBram Moolenaar {
3571a9b579f3SBram Moolenaar *pp += 3;
3572a9b579f3SBram Moolenaar len = get_id_len(pp) + 3;
3573a9b579f3SBram Moolenaar return vim_strnsave(start, len);
3574a9b579f3SBram Moolenaar }
3575a9b579f3SBram Moolenaar
3576e38eab22SBram Moolenaar // A name starting with "<SID>" or "<SNR>" is local to a script. But
3577e38eab22SBram Moolenaar // don't skip over "s:", get_lval() needs it for "s:dict.func".
3578a9b579f3SBram Moolenaar lead = eval_fname_script(start);
3579a9b579f3SBram Moolenaar if (lead > 2)
3580a9b579f3SBram Moolenaar start += lead;
3581a9b579f3SBram Moolenaar
3582e38eab22SBram Moolenaar // Note that TFN_ flags use the same values as GLV_ flags.
35836e65d594SBram Moolenaar end = get_lval(start, NULL, &lv, FALSE, skip, flags | GLV_READ_ONLY,
3584a9b579f3SBram Moolenaar lead > 2 ? 0 : FNE_CHECK_START);
3585a9b579f3SBram Moolenaar if (end == start)
3586a9b579f3SBram Moolenaar {
3587a9b579f3SBram Moolenaar if (!skip)
35887b5d5442SBram Moolenaar emsg(_(e_function_name));
3589a9b579f3SBram Moolenaar goto theend;
3590a9b579f3SBram Moolenaar }
3591a9b579f3SBram Moolenaar if (end == NULL || (lv.ll_tv != NULL && (lead > 2 || lv.ll_range)))
3592a9b579f3SBram Moolenaar {
3593a9b579f3SBram Moolenaar /*
3594a9b579f3SBram Moolenaar * Report an invalid expression in braces, unless the expression
3595a9b579f3SBram Moolenaar * evaluation has been cancelled due to an aborting error, an
3596a9b579f3SBram Moolenaar * interrupt, or an exception.
3597a9b579f3SBram Moolenaar */
3598a9b579f3SBram Moolenaar if (!aborting())
3599a9b579f3SBram Moolenaar {
3600a9b579f3SBram Moolenaar if (end != NULL)
3601f9e3e09fSBram Moolenaar semsg(_(e_invarg2), start);
3602a9b579f3SBram Moolenaar }
3603a9b579f3SBram Moolenaar else
3604a9b579f3SBram Moolenaar *pp = find_name_end(start, NULL, NULL, FNE_INCL_BR);
3605a9b579f3SBram Moolenaar goto theend;
3606a9b579f3SBram Moolenaar }
3607a9b579f3SBram Moolenaar
3608a9b579f3SBram Moolenaar if (lv.ll_tv != NULL)
3609a9b579f3SBram Moolenaar {
3610a9b579f3SBram Moolenaar if (fdp != NULL)
3611a9b579f3SBram Moolenaar {
3612a9b579f3SBram Moolenaar fdp->fd_dict = lv.ll_dict;
3613a9b579f3SBram Moolenaar fdp->fd_newkey = lv.ll_newkey;
3614a9b579f3SBram Moolenaar lv.ll_newkey = NULL;
3615a9b579f3SBram Moolenaar fdp->fd_di = lv.ll_di;
3616a9b579f3SBram Moolenaar }
3617a9b579f3SBram Moolenaar if (lv.ll_tv->v_type == VAR_FUNC && lv.ll_tv->vval.v_string != NULL)
3618a9b579f3SBram Moolenaar {
3619a9b579f3SBram Moolenaar name = vim_strsave(lv.ll_tv->vval.v_string);
3620a9b579f3SBram Moolenaar *pp = end;
3621a9b579f3SBram Moolenaar }
3622a9b579f3SBram Moolenaar else if (lv.ll_tv->v_type == VAR_PARTIAL
3623a9b579f3SBram Moolenaar && lv.ll_tv->vval.v_partial != NULL)
3624a9b579f3SBram Moolenaar {
3625437bafe4SBram Moolenaar name = vim_strsave(partial_name(lv.ll_tv->vval.v_partial));
3626a9b579f3SBram Moolenaar *pp = end;
3627a9b579f3SBram Moolenaar if (partial != NULL)
3628a9b579f3SBram Moolenaar *partial = lv.ll_tv->vval.v_partial;
3629a9b579f3SBram Moolenaar }
3630a9b579f3SBram Moolenaar else
3631a9b579f3SBram Moolenaar {
3632a9b579f3SBram Moolenaar if (!skip && !(flags & TFN_QUIET) && (fdp == NULL
3633a9b579f3SBram Moolenaar || lv.ll_dict == NULL || fdp->fd_newkey == NULL))
3634f9e3e09fSBram Moolenaar emsg(_(e_funcref));
3635a9b579f3SBram Moolenaar else
3636a9b579f3SBram Moolenaar *pp = end;
3637a9b579f3SBram Moolenaar name = NULL;
3638a9b579f3SBram Moolenaar }
3639a9b579f3SBram Moolenaar goto theend;
3640a9b579f3SBram Moolenaar }
3641a9b579f3SBram Moolenaar
3642a9b579f3SBram Moolenaar if (lv.ll_name == NULL)
3643a9b579f3SBram Moolenaar {
3644e38eab22SBram Moolenaar // Error found, but continue after the function name.
3645a9b579f3SBram Moolenaar *pp = end;
3646a9b579f3SBram Moolenaar goto theend;
3647a9b579f3SBram Moolenaar }
3648a9b579f3SBram Moolenaar
3649e38eab22SBram Moolenaar // Check if the name is a Funcref. If so, use the value.
3650a9b579f3SBram Moolenaar if (lv.ll_exp_name != NULL)
3651a9b579f3SBram Moolenaar {
3652a9b579f3SBram Moolenaar len = (int)STRLEN(lv.ll_exp_name);
365332b3f820SBram Moolenaar name = deref_func_name(lv.ll_exp_name, &len, partial, type,
3654a9b579f3SBram Moolenaar flags & TFN_NO_AUTOLOAD);
3655a9b579f3SBram Moolenaar if (name == lv.ll_exp_name)
3656a9b579f3SBram Moolenaar name = NULL;
3657a9b579f3SBram Moolenaar }
3658b54c3ff3SBram Moolenaar else if (!(flags & TFN_NO_DEREF))
3659a9b579f3SBram Moolenaar {
3660a9b579f3SBram Moolenaar len = (int)(end - *pp);
366132b3f820SBram Moolenaar name = deref_func_name(*pp, &len, partial, type,
366232b3f820SBram Moolenaar flags & TFN_NO_AUTOLOAD);
3663a9b579f3SBram Moolenaar if (name == *pp)
3664a9b579f3SBram Moolenaar name = NULL;
3665a9b579f3SBram Moolenaar }
3666a9b579f3SBram Moolenaar if (name != NULL)
3667a9b579f3SBram Moolenaar {
3668a9b579f3SBram Moolenaar name = vim_strsave(name);
3669a9b579f3SBram Moolenaar *pp = end;
3670a9b579f3SBram Moolenaar if (STRNCMP(name, "<SNR>", 5) == 0)
3671a9b579f3SBram Moolenaar {
3672e38eab22SBram Moolenaar // Change "<SNR>" to the byte sequence.
3673a9b579f3SBram Moolenaar name[0] = K_SPECIAL;
3674a9b579f3SBram Moolenaar name[1] = KS_EXTRA;
3675a9b579f3SBram Moolenaar name[2] = (int)KE_SNR;
3676a9b579f3SBram Moolenaar mch_memmove(name + 3, name + 5, STRLEN(name + 5) + 1);
3677a9b579f3SBram Moolenaar }
3678a9b579f3SBram Moolenaar goto theend;
3679a9b579f3SBram Moolenaar }
3680a9b579f3SBram Moolenaar
3681a9b579f3SBram Moolenaar if (lv.ll_exp_name != NULL)
3682a9b579f3SBram Moolenaar {
3683a9b579f3SBram Moolenaar len = (int)STRLEN(lv.ll_exp_name);
3684a9b579f3SBram Moolenaar if (lead <= 2 && lv.ll_name == lv.ll_exp_name
3685a9b579f3SBram Moolenaar && STRNCMP(lv.ll_name, "s:", 2) == 0)
3686a9b579f3SBram Moolenaar {
3687e38eab22SBram Moolenaar // When there was "s:" already or the name expanded to get a
3688e38eab22SBram Moolenaar // leading "s:" then remove it.
3689a9b579f3SBram Moolenaar lv.ll_name += 2;
3690a9b579f3SBram Moolenaar len -= 2;
3691a9b579f3SBram Moolenaar lead = 2;
3692a9b579f3SBram Moolenaar }
3693a9b579f3SBram Moolenaar }
3694a9b579f3SBram Moolenaar else
3695a9b579f3SBram Moolenaar {
3696e38eab22SBram Moolenaar // skip over "s:" and "g:"
3697a9b579f3SBram Moolenaar if (lead == 2 || (lv.ll_name[0] == 'g' && lv.ll_name[1] == ':'))
36984c17ad94SBram Moolenaar {
36994c17ad94SBram Moolenaar if (is_global != NULL && lv.ll_name[0] == 'g')
37004c17ad94SBram Moolenaar *is_global = TRUE;
3701a9b579f3SBram Moolenaar lv.ll_name += 2;
37024c17ad94SBram Moolenaar }
3703a9b579f3SBram Moolenaar len = (int)(end - lv.ll_name);
3704a9b579f3SBram Moolenaar }
37057b5d5442SBram Moolenaar if (len <= 0)
37067b5d5442SBram Moolenaar {
37077b5d5442SBram Moolenaar if (!skip)
37087b5d5442SBram Moolenaar emsg(_(e_function_name));
37097b5d5442SBram Moolenaar goto theend;
37107b5d5442SBram Moolenaar }
3711a9b579f3SBram Moolenaar
371217f700acSBram Moolenaar // In Vim9 script a user function is script-local by default, unless it
371317f700acSBram Moolenaar // starts with a lower case character: dict.func().
3714eb6880b6SBram Moolenaar vim9script = ASCII_ISUPPER(*start) && in_vim9script();
371517f700acSBram Moolenaar if (vim9script)
371617f700acSBram Moolenaar {
371717f700acSBram Moolenaar char_u *p;
371817f700acSBram Moolenaar
371917f700acSBram Moolenaar // SomeScript#func() is a global function.
372017f700acSBram Moolenaar for (p = start; *p != NUL && *p != '('; ++p)
372117f700acSBram Moolenaar if (*p == AUTOLOAD_CHAR)
372217f700acSBram Moolenaar vim9script = FALSE;
372317f700acSBram Moolenaar }
37248a7d6542SBram Moolenaar
3725a9b579f3SBram Moolenaar /*
3726a9b579f3SBram Moolenaar * Copy the function name to allocated memory.
3727a9b579f3SBram Moolenaar * Accept <SID>name() inside a script, translate into <SNR>123_name().
3728a9b579f3SBram Moolenaar * Accept <SNR>123_name() outside a script.
3729a9b579f3SBram Moolenaar */
3730a9b579f3SBram Moolenaar if (skip)
3731e38eab22SBram Moolenaar lead = 0; // do nothing
37328a7d6542SBram Moolenaar else if (lead > 0 || vim9script)
3733a9b579f3SBram Moolenaar {
37348a7d6542SBram Moolenaar if (!vim9script)
3735a9b579f3SBram Moolenaar lead = 3;
37368a7d6542SBram Moolenaar if (vim9script || (lv.ll_exp_name != NULL
37378a7d6542SBram Moolenaar && eval_fname_sid(lv.ll_exp_name))
3738a9b579f3SBram Moolenaar || eval_fname_sid(*pp))
3739a9b579f3SBram Moolenaar {
37408a7d6542SBram Moolenaar // It's script-local, "s:" or "<SID>"
3741f29c1c6aSBram Moolenaar if (current_sctx.sc_sid <= 0)
3742a9b579f3SBram Moolenaar {
3743f9e3e09fSBram Moolenaar emsg(_(e_usingsid));
3744a9b579f3SBram Moolenaar goto theend;
3745a9b579f3SBram Moolenaar }
3746f29c1c6aSBram Moolenaar sprintf((char *)sid_buf, "%ld_", (long)current_sctx.sc_sid);
37478a7d6542SBram Moolenaar if (vim9script)
37488a7d6542SBram Moolenaar extra = 3 + (int)STRLEN(sid_buf);
37498a7d6542SBram Moolenaar else
3750a9b579f3SBram Moolenaar lead += (int)STRLEN(sid_buf);
3751a9b579f3SBram Moolenaar }
3752a9b579f3SBram Moolenaar }
375322f17a29SBram Moolenaar else if (!(flags & TFN_INT) && (builtin_function(lv.ll_name, len)
375422f17a29SBram Moolenaar || (in_vim9script() && *lv.ll_name == '_')))
3755a9b579f3SBram Moolenaar {
3756f9e3e09fSBram Moolenaar semsg(_("E128: Function name must start with a capital or \"s:\": %s"),
3757a9b579f3SBram Moolenaar start);
3758a9b579f3SBram Moolenaar goto theend;
3759a9b579f3SBram Moolenaar }
3760b54c3ff3SBram Moolenaar if (!skip && !(flags & TFN_QUIET) && !(flags & TFN_NO_DEREF))
3761a9b579f3SBram Moolenaar {
3762a9b579f3SBram Moolenaar char_u *cp = vim_strchr(lv.ll_name, ':');
3763a9b579f3SBram Moolenaar
3764a9b579f3SBram Moolenaar if (cp != NULL && cp < end)
3765a9b579f3SBram Moolenaar {
3766f9e3e09fSBram Moolenaar semsg(_("E884: Function name cannot contain a colon: %s"), start);
3767a9b579f3SBram Moolenaar goto theend;
3768a9b579f3SBram Moolenaar }
3769a9b579f3SBram Moolenaar }
3770a9b579f3SBram Moolenaar
37718a7d6542SBram Moolenaar name = alloc(len + lead + extra + 1);
3772a9b579f3SBram Moolenaar if (name != NULL)
3773a9b579f3SBram Moolenaar {
37749a5e5a3eSBram Moolenaar if (!skip && (lead > 0 || vim9script))
3775a9b579f3SBram Moolenaar {
3776a9b579f3SBram Moolenaar name[0] = K_SPECIAL;
3777a9b579f3SBram Moolenaar name[1] = KS_EXTRA;
3778a9b579f3SBram Moolenaar name[2] = (int)KE_SNR;
37798a7d6542SBram Moolenaar if (vim9script || lead > 3) // If it's "<SID>"
3780a9b579f3SBram Moolenaar STRCPY(name + 3, sid_buf);
3781a9b579f3SBram Moolenaar }
37828a7d6542SBram Moolenaar mch_memmove(name + lead + extra, lv.ll_name, (size_t)len);
37838a7d6542SBram Moolenaar name[lead + extra + len] = NUL;
3784a9b579f3SBram Moolenaar }
3785a9b579f3SBram Moolenaar *pp = end;
3786a9b579f3SBram Moolenaar
3787a9b579f3SBram Moolenaar theend:
3788a9b579f3SBram Moolenaar clear_lval(&lv);
3789a9b579f3SBram Moolenaar return name;
3790a9b579f3SBram Moolenaar }
3791a9b579f3SBram Moolenaar
3792a9b579f3SBram Moolenaar /*
3793a26b9700SBram Moolenaar * Assuming "name" is the result of trans_function_name() and it was prefixed
3794a26b9700SBram Moolenaar * to use the script-local name, return the unmodified name (points into
3795a26b9700SBram Moolenaar * "name"). Otherwise return NULL.
3796a26b9700SBram Moolenaar * This can be used to first search for a script-local function and fall back
3797a26b9700SBram Moolenaar * to the global function if not found.
3798a26b9700SBram Moolenaar */
3799a26b9700SBram Moolenaar char_u *
untrans_function_name(char_u * name)3800a26b9700SBram Moolenaar untrans_function_name(char_u *name)
3801a26b9700SBram Moolenaar {
3802a26b9700SBram Moolenaar char_u *p;
3803a26b9700SBram Moolenaar
3804eb6880b6SBram Moolenaar if (*name == K_SPECIAL && in_vim9script())
3805a26b9700SBram Moolenaar {
3806a26b9700SBram Moolenaar p = vim_strchr(name, '_');
3807a26b9700SBram Moolenaar if (p != NULL)
3808a26b9700SBram Moolenaar return p + 1;
3809a26b9700SBram Moolenaar }
3810a26b9700SBram Moolenaar return NULL;
3811a26b9700SBram Moolenaar }
3812a26b9700SBram Moolenaar
3813a26b9700SBram Moolenaar /*
38143fffa971SBram Moolenaar * List functions. When "regmatch" is NULL all of then.
38153fffa971SBram Moolenaar * Otherwise functions matching "regmatch".
38163fffa971SBram Moolenaar */
38176abdcf82SBram Moolenaar void
list_functions(regmatch_T * regmatch)38183fffa971SBram Moolenaar list_functions(regmatch_T *regmatch)
38193fffa971SBram Moolenaar {
38201f22cc5cSBram Moolenaar int changed = func_hashtab.ht_changed;
38211f22cc5cSBram Moolenaar long_u todo = func_hashtab.ht_used;
38223fffa971SBram Moolenaar hashitem_T *hi;
38233fffa971SBram Moolenaar
38241f22cc5cSBram Moolenaar for (hi = func_hashtab.ht_array; todo > 0 && !got_int; ++hi)
38253fffa971SBram Moolenaar {
38263fffa971SBram Moolenaar if (!HASHITEM_EMPTY(hi))
38273fffa971SBram Moolenaar {
38283fffa971SBram Moolenaar ufunc_T *fp = HI2UF(hi);
38293fffa971SBram Moolenaar
38303fffa971SBram Moolenaar --todo;
38313fffa971SBram Moolenaar if ((fp->uf_flags & FC_DEAD) == 0
38323fffa971SBram Moolenaar && (regmatch == NULL
38333fffa971SBram Moolenaar ? !message_filtered(fp->uf_name)
38343fffa971SBram Moolenaar && !func_name_refcount(fp->uf_name)
38353fffa971SBram Moolenaar : !isdigit(*fp->uf_name)
38363fffa971SBram Moolenaar && vim_regexec(regmatch, fp->uf_name, 0)))
38373fffa971SBram Moolenaar {
38383fffa971SBram Moolenaar list_func_head(fp, FALSE);
38391f22cc5cSBram Moolenaar if (changed != func_hashtab.ht_changed)
38403fffa971SBram Moolenaar {
38413fffa971SBram Moolenaar emsg(_("E454: function list was modified"));
38423fffa971SBram Moolenaar return;
38433fffa971SBram Moolenaar }
38443fffa971SBram Moolenaar }
38453fffa971SBram Moolenaar }
38463fffa971SBram Moolenaar }
38473fffa971SBram Moolenaar }
38483fffa971SBram Moolenaar
38493fffa971SBram Moolenaar /*
385004b12697SBram Moolenaar * ":function" also supporting nested ":def".
385138ddf333SBram Moolenaar * When "name_arg" is not NULL this is a nested function, using "name_arg" for
385238ddf333SBram Moolenaar * the function name.
385304b12697SBram Moolenaar * Returns a pointer to the function or NULL if no function defined.
3854a9b579f3SBram Moolenaar */
385504b12697SBram Moolenaar ufunc_T *
define_function(exarg_T * eap,char_u * name_arg)3856fbbcd003SBram Moolenaar define_function(exarg_T *eap, char_u *name_arg)
3857a9b579f3SBram Moolenaar {
385853564f7cSBram Moolenaar char_u *line_to_free = NULL;
3859a9b579f3SBram Moolenaar int j;
3860a9b579f3SBram Moolenaar int c;
3861a9b579f3SBram Moolenaar int saved_did_emsg;
386204b12697SBram Moolenaar char_u *name = name_arg;
38634c17ad94SBram Moolenaar int is_global = FALSE;
3864a9b579f3SBram Moolenaar char_u *p;
3865a9b579f3SBram Moolenaar char_u *arg;
3866cef1270dSBram Moolenaar char_u *whitep;
3867a9b579f3SBram Moolenaar char_u *line_arg = NULL;
3868a9b579f3SBram Moolenaar garray_T newargs;
38698a7d6542SBram Moolenaar garray_T argtypes;
387042ae78cfSBram Moolenaar garray_T default_args;
3871a9b579f3SBram Moolenaar garray_T newlines;
3872a9b579f3SBram Moolenaar int varargs = FALSE;
3873a9b579f3SBram Moolenaar int flags = 0;
38748a7d6542SBram Moolenaar char_u *ret_type = NULL;
387504b12697SBram Moolenaar ufunc_T *fp = NULL;
3876437bafe4SBram Moolenaar int overwrite = FALSE;
3877a9b579f3SBram Moolenaar dictitem_T *v;
3878a9b579f3SBram Moolenaar funcdict_T fudi;
3879e38eab22SBram Moolenaar static int func_nr = 0; // number for nameless function
3880a9b579f3SBram Moolenaar int paren;
3881a9b579f3SBram Moolenaar hashitem_T *hi;
3882bc2cfe46SBram Moolenaar linenr_T sourcing_lnum_top;
3883e7e4838fSBram Moolenaar int vim9script = in_vim9script();
3884eef2102eSBram Moolenaar imported_T *import = NULL;
3885a9b579f3SBram Moolenaar
3886a9b579f3SBram Moolenaar /*
3887a9b579f3SBram Moolenaar * ":function" without argument: list functions.
3888a9b579f3SBram Moolenaar */
3889a72cfb80SBram Moolenaar if (ends_excmd2(eap->cmd, eap->arg))
3890a9b579f3SBram Moolenaar {
3891a9b579f3SBram Moolenaar if (!eap->skip)
38923fffa971SBram Moolenaar list_functions(NULL);
389363b91736SBram Moolenaar set_nextcmd(eap, eap->arg);
389404b12697SBram Moolenaar return NULL;
3895a9b579f3SBram Moolenaar }
3896a9b579f3SBram Moolenaar
3897a9b579f3SBram Moolenaar /*
3898a9b579f3SBram Moolenaar * ":function /pat": list functions matching pattern.
3899a9b579f3SBram Moolenaar */
3900a9b579f3SBram Moolenaar if (*eap->arg == '/')
3901a9b579f3SBram Moolenaar {
3902e8c4abbbSBram Moolenaar p = skip_regexp(eap->arg + 1, '/', TRUE);
3903a9b579f3SBram Moolenaar if (!eap->skip)
3904a9b579f3SBram Moolenaar {
3905a9b579f3SBram Moolenaar regmatch_T regmatch;
3906a9b579f3SBram Moolenaar
3907a9b579f3SBram Moolenaar c = *p;
3908a9b579f3SBram Moolenaar *p = NUL;
3909a9b579f3SBram Moolenaar regmatch.regprog = vim_regcomp(eap->arg + 1, RE_MAGIC);
3910a9b579f3SBram Moolenaar *p = c;
3911a9b579f3SBram Moolenaar if (regmatch.regprog != NULL)
3912a9b579f3SBram Moolenaar {
3913a9b579f3SBram Moolenaar regmatch.rm_ic = p_ic;
39143fffa971SBram Moolenaar list_functions(®match);
3915a9b579f3SBram Moolenaar vim_regfree(regmatch.regprog);
3916a9b579f3SBram Moolenaar }
3917a9b579f3SBram Moolenaar }
3918a9b579f3SBram Moolenaar if (*p == '/')
3919a9b579f3SBram Moolenaar ++p;
392063b91736SBram Moolenaar set_nextcmd(eap, p);
392104b12697SBram Moolenaar return NULL;
3922a9b579f3SBram Moolenaar }
3923a9b579f3SBram Moolenaar
39248a7d6542SBram Moolenaar ga_init(&newargs);
39258a7d6542SBram Moolenaar ga_init(&argtypes);
39268a7d6542SBram Moolenaar ga_init(&default_args);
39278a7d6542SBram Moolenaar
3928a9b579f3SBram Moolenaar /*
3929a9b579f3SBram Moolenaar * Get the function name. There are these situations:
3930a9b579f3SBram Moolenaar * func normal function name
3931a9b579f3SBram Moolenaar * "name" == func, "fudi.fd_dict" == NULL
3932a9b579f3SBram Moolenaar * dict.func new dictionary entry
3933a9b579f3SBram Moolenaar * "name" == NULL, "fudi.fd_dict" set,
3934a9b579f3SBram Moolenaar * "fudi.fd_di" == NULL, "fudi.fd_newkey" == func
3935a9b579f3SBram Moolenaar * dict.func existing dict entry with a Funcref
3936a9b579f3SBram Moolenaar * "name" == func, "fudi.fd_dict" set,
3937a9b579f3SBram Moolenaar * "fudi.fd_di" set, "fudi.fd_newkey" == NULL
3938a9b579f3SBram Moolenaar * dict.func existing dict entry that's not a Funcref
3939a9b579f3SBram Moolenaar * "name" == NULL, "fudi.fd_dict" set,
3940a9b579f3SBram Moolenaar * "fudi.fd_di" set, "fudi.fd_newkey" == NULL
3941a9b579f3SBram Moolenaar * s:func script-local function name
3942a9b579f3SBram Moolenaar * g:func global function name, same as "func"
3943a9b579f3SBram Moolenaar */
3944a9b579f3SBram Moolenaar p = eap->arg;
394504b12697SBram Moolenaar if (name_arg != NULL)
394604b12697SBram Moolenaar {
394704b12697SBram Moolenaar // nested function, argument is (args).
394804b12697SBram Moolenaar paren = TRUE;
394904b12697SBram Moolenaar CLEAR_FIELD(fudi);
395004b12697SBram Moolenaar }
395104b12697SBram Moolenaar else
395204b12697SBram Moolenaar {
3953b657198cSBram Moolenaar if (STRNCMP(p, "<lambda>", 8) == 0)
3954b657198cSBram Moolenaar {
3955b657198cSBram Moolenaar p += 8;
3956b657198cSBram Moolenaar (void)getdigits(&p);
3957b657198cSBram Moolenaar name = vim_strnsave(eap->arg, p - eap->arg);
3958b657198cSBram Moolenaar CLEAR_FIELD(fudi);
3959b657198cSBram Moolenaar }
3960b657198cSBram Moolenaar else
39614c17ad94SBram Moolenaar name = trans_function_name(&p, &is_global, eap->skip,
396232b3f820SBram Moolenaar TFN_NO_AUTOLOAD, &fudi, NULL, NULL);
3963a9b579f3SBram Moolenaar paren = (vim_strchr(p, '(') != NULL);
3964a9b579f3SBram Moolenaar if (name == NULL && (fudi.fd_dict == NULL || !paren) && !eap->skip)
3965a9b579f3SBram Moolenaar {
3966a9b579f3SBram Moolenaar /*
3967a9b579f3SBram Moolenaar * Return on an invalid expression in braces, unless the expression
3968a9b579f3SBram Moolenaar * evaluation has been cancelled due to an aborting error, an
3969a9b579f3SBram Moolenaar * interrupt, or an exception.
3970a9b579f3SBram Moolenaar */
3971a9b579f3SBram Moolenaar if (!aborting())
3972a9b579f3SBram Moolenaar {
3973a9b579f3SBram Moolenaar if (!eap->skip && fudi.fd_newkey != NULL)
3974f9e3e09fSBram Moolenaar semsg(_(e_dictkey), fudi.fd_newkey);
3975a9b579f3SBram Moolenaar vim_free(fudi.fd_newkey);
397604b12697SBram Moolenaar return NULL;
3977a9b579f3SBram Moolenaar }
3978a9b579f3SBram Moolenaar else
3979a9b579f3SBram Moolenaar eap->skip = TRUE;
3980a9b579f3SBram Moolenaar }
398104b12697SBram Moolenaar }
3982a9b579f3SBram Moolenaar
3983e38eab22SBram Moolenaar // An error in a function call during evaluation of an expression in magic
3984e38eab22SBram Moolenaar // braces should not cause the function not to be defined.
3985a9b579f3SBram Moolenaar saved_did_emsg = did_emsg;
3986a9b579f3SBram Moolenaar did_emsg = FALSE;
3987a9b579f3SBram Moolenaar
3988a9b579f3SBram Moolenaar /*
3989a9b579f3SBram Moolenaar * ":function func" with only function name: list function.
3990a9b579f3SBram Moolenaar */
3991a9b579f3SBram Moolenaar if (!paren)
3992a9b579f3SBram Moolenaar {
3993a9b579f3SBram Moolenaar if (!ends_excmd(*skipwhite(p)))
3994a9b579f3SBram Moolenaar {
39952d06bfdeSBram Moolenaar semsg(_(e_trailing_arg), p);
3996a9b579f3SBram Moolenaar goto ret_free;
3997a9b579f3SBram Moolenaar }
399863b91736SBram Moolenaar set_nextcmd(eap, p);
3999a9b579f3SBram Moolenaar if (eap->nextcmd != NULL)
4000a9b579f3SBram Moolenaar *p = NUL;
4001a9b579f3SBram Moolenaar if (!eap->skip && !got_int)
4002a9b579f3SBram Moolenaar {
40034c17ad94SBram Moolenaar fp = find_func(name, is_global, NULL);
4004a26b9700SBram Moolenaar if (fp == NULL && ASCII_ISUPPER(*eap->arg))
4005a26b9700SBram Moolenaar {
4006a26b9700SBram Moolenaar char_u *up = untrans_function_name(name);
4007a26b9700SBram Moolenaar
4008a26b9700SBram Moolenaar // With Vim9 script the name was made script-local, if not
4009a26b9700SBram Moolenaar // found try again with the original name.
4010ec9749f3SBram Moolenaar if (up != NULL)
40114c17ad94SBram Moolenaar fp = find_func(up, FALSE, NULL);
4012a26b9700SBram Moolenaar }
4013a26b9700SBram Moolenaar
4014a9b579f3SBram Moolenaar if (fp != NULL)
4015a9b579f3SBram Moolenaar {
4016a9b579f3SBram Moolenaar list_func_head(fp, TRUE);
4017a9b579f3SBram Moolenaar for (j = 0; j < fp->uf_lines.ga_len && !got_int; ++j)
4018a9b579f3SBram Moolenaar {
4019a9b579f3SBram Moolenaar if (FUNCLINE(fp, j) == NULL)
4020a9b579f3SBram Moolenaar continue;
4021a9b579f3SBram Moolenaar msg_putchar('\n');
4022a9b579f3SBram Moolenaar msg_outnum((long)(j + 1));
4023a9b579f3SBram Moolenaar if (j < 9)
4024a9b579f3SBram Moolenaar msg_putchar(' ');
4025a9b579f3SBram Moolenaar if (j < 99)
4026a9b579f3SBram Moolenaar msg_putchar(' ');
4027a9b579f3SBram Moolenaar msg_prt_line(FUNCLINE(fp, j), FALSE);
4028e38eab22SBram Moolenaar out_flush(); // show a line at a time
4029a9b579f3SBram Moolenaar ui_breakcheck();
4030a9b579f3SBram Moolenaar }
4031a9b579f3SBram Moolenaar if (!got_int)
4032a9b579f3SBram Moolenaar {
4033a9b579f3SBram Moolenaar msg_putchar('\n');
40340cb5bcf5SBram Moolenaar if (fp->uf_def_status != UF_NOT_COMPILED)
40358a7d6542SBram Moolenaar msg_puts(" enddef");
40368a7d6542SBram Moolenaar else
403732526b3cSBram Moolenaar msg_puts(" endfunction");
4038a9b579f3SBram Moolenaar }
4039a9b579f3SBram Moolenaar }
4040a9b579f3SBram Moolenaar else
4041a26b9700SBram Moolenaar emsg_funcname(N_("E123: Undefined function: %s"), eap->arg);
4042a9b579f3SBram Moolenaar }
4043a9b579f3SBram Moolenaar goto ret_free;
4044a9b579f3SBram Moolenaar }
4045a9b579f3SBram Moolenaar
4046a9b579f3SBram Moolenaar /*
4047a9b579f3SBram Moolenaar * ":function name(arg1, arg2)" Define function.
4048a9b579f3SBram Moolenaar */
4049a9b579f3SBram Moolenaar p = skipwhite(p);
4050a9b579f3SBram Moolenaar if (*p != '(')
4051a9b579f3SBram Moolenaar {
4052a9b579f3SBram Moolenaar if (!eap->skip)
4053a9b579f3SBram Moolenaar {
4054f9e3e09fSBram Moolenaar semsg(_("E124: Missing '(': %s"), eap->arg);
4055a9b579f3SBram Moolenaar goto ret_free;
4056a9b579f3SBram Moolenaar }
4057e38eab22SBram Moolenaar // attempt to continue by skipping some text
4058a9b579f3SBram Moolenaar if (vim_strchr(p, '(') != NULL)
4059a9b579f3SBram Moolenaar p = vim_strchr(p, '(');
4060a9b579f3SBram Moolenaar }
4061a9b579f3SBram Moolenaar
40624efd9948SBram Moolenaar if ((vim9script || eap->cmdidx == CMD_def) && VIM_ISWHITE(p[-1]))
40634efd9948SBram Moolenaar {
4064ba98fb54SBram Moolenaar semsg(_(e_no_white_space_allowed_before_str_str), "(", p - 1);
40654efd9948SBram Moolenaar goto ret_free;
40664efd9948SBram Moolenaar }
40674efd9948SBram Moolenaar
4068925e9fd6SBram Moolenaar // In Vim9 script only global functions can be redefined.
4069925e9fd6SBram Moolenaar if (vim9script && eap->forceit && !is_global)
4070925e9fd6SBram Moolenaar {
4071925e9fd6SBram Moolenaar emsg(_(e_nobang));
4072925e9fd6SBram Moolenaar goto ret_free;
4073925e9fd6SBram Moolenaar }
4074925e9fd6SBram Moolenaar
40757a6eaa06SBram Moolenaar ga_init2(&newlines, (int)sizeof(char_u *), 10);
4076a9b579f3SBram Moolenaar
407704b12697SBram Moolenaar if (!eap->skip && name_arg == NULL)
4078a9b579f3SBram Moolenaar {
4079e38eab22SBram Moolenaar // Check the name of the function. Unless it's a dictionary function
4080e38eab22SBram Moolenaar // (that we are overwriting).
4081a9b579f3SBram Moolenaar if (name != NULL)
4082a9b579f3SBram Moolenaar arg = name;
4083a9b579f3SBram Moolenaar else
4084a9b579f3SBram Moolenaar arg = fudi.fd_newkey;
4085a9b579f3SBram Moolenaar if (arg != NULL && (fudi.fd_di == NULL
4086a9b579f3SBram Moolenaar || (fudi.fd_di->di_tv.v_type != VAR_FUNC
4087a9b579f3SBram Moolenaar && fudi.fd_di->di_tv.v_type != VAR_PARTIAL)))
4088a9b579f3SBram Moolenaar {
4089a9b579f3SBram Moolenaar if (*arg == K_SPECIAL)
4090a9b579f3SBram Moolenaar j = 3;
4091a9b579f3SBram Moolenaar else
4092a9b579f3SBram Moolenaar j = 0;
4093a9b579f3SBram Moolenaar while (arg[j] != NUL && (j == 0 ? eval_isnamec1(arg[j])
4094a9b579f3SBram Moolenaar : eval_isnamec(arg[j])))
4095a9b579f3SBram Moolenaar ++j;
4096a9b579f3SBram Moolenaar if (arg[j] != NUL)
4097a9b579f3SBram Moolenaar emsg_funcname((char *)e_invarg2, arg);
4098a9b579f3SBram Moolenaar }
4099e38eab22SBram Moolenaar // Disallow using the g: dict.
4100a9b579f3SBram Moolenaar if (fudi.fd_dict != NULL && fudi.fd_dict->dv_scope == VAR_DEF_SCOPE)
4101f9e3e09fSBram Moolenaar emsg(_("E862: Cannot use g: here"));
4102a9b579f3SBram Moolenaar }
4103a9b579f3SBram Moolenaar
41045e774c75SBram Moolenaar // This may get more lines and make the pointers into the first line
41055e774c75SBram Moolenaar // invalid.
4106cef1270dSBram Moolenaar ++p;
41078a7d6542SBram Moolenaar if (get_function_args(&p, ')', &newargs,
4108b4d16cb1SBram Moolenaar eap->cmdidx == CMD_def ? &argtypes : NULL, FALSE,
4109057e84afSBram Moolenaar NULL, &varargs, &default_args, eap->skip,
41105e774c75SBram Moolenaar eap, &line_to_free) == FAIL)
4111a9b579f3SBram Moolenaar goto errret_2;
4112cef1270dSBram Moolenaar whitep = p;
4113a9b579f3SBram Moolenaar
41148a7d6542SBram Moolenaar if (eap->cmdidx == CMD_def)
41158a7d6542SBram Moolenaar {
41168a7d6542SBram Moolenaar // find the return type: :def Func(): type
411733ea9fd4SBram Moolenaar if (*skipwhite(p) == ':')
41188a7d6542SBram Moolenaar {
411933ea9fd4SBram Moolenaar if (*p != ':')
412033ea9fd4SBram Moolenaar {
412133ea9fd4SBram Moolenaar semsg(_(e_no_white_space_allowed_before_colon_str), p);
412233ea9fd4SBram Moolenaar p = skipwhite(p);
412333ea9fd4SBram Moolenaar }
412433ea9fd4SBram Moolenaar else if (!IS_WHITE_OR_NUL(p[1]))
412533ea9fd4SBram Moolenaar semsg(_(e_white_space_required_after_str_str), ":", p);
41268a7d6542SBram Moolenaar ret_type = skipwhite(p + 1);
41274fc224caSBram Moolenaar p = skip_type(ret_type, FALSE);
41288a7d6542SBram Moolenaar if (p > ret_type)
41295e774c75SBram Moolenaar {
413071ccd03eSBram Moolenaar ret_type = vim_strnsave(ret_type, p - ret_type);
4131cef1270dSBram Moolenaar whitep = p;
41328a7d6542SBram Moolenaar p = skipwhite(p);
41335e774c75SBram Moolenaar }
41348a7d6542SBram Moolenaar else
41355e774c75SBram Moolenaar {
4136451c2e35SBram Moolenaar semsg(_(e_expected_type_str), ret_type);
4137b8ce6b00SBram Moolenaar ret_type = NULL;
41388a7d6542SBram Moolenaar }
41398a7d6542SBram Moolenaar }
4140e7e4838fSBram Moolenaar p = skipwhite(p);
41415e774c75SBram Moolenaar }
41428a7d6542SBram Moolenaar else
4143e38eab22SBram Moolenaar // find extra arguments "range", "dict", "abort" and "closure"
4144a9b579f3SBram Moolenaar for (;;)
4145a9b579f3SBram Moolenaar {
4146cef1270dSBram Moolenaar whitep = p;
4147a9b579f3SBram Moolenaar p = skipwhite(p);
4148a9b579f3SBram Moolenaar if (STRNCMP(p, "range", 5) == 0)
4149a9b579f3SBram Moolenaar {
4150a9b579f3SBram Moolenaar flags |= FC_RANGE;
4151a9b579f3SBram Moolenaar p += 5;
4152a9b579f3SBram Moolenaar }
4153a9b579f3SBram Moolenaar else if (STRNCMP(p, "dict", 4) == 0)
4154a9b579f3SBram Moolenaar {
4155a9b579f3SBram Moolenaar flags |= FC_DICT;
4156a9b579f3SBram Moolenaar p += 4;
4157a9b579f3SBram Moolenaar }
4158a9b579f3SBram Moolenaar else if (STRNCMP(p, "abort", 5) == 0)
4159a9b579f3SBram Moolenaar {
4160a9b579f3SBram Moolenaar flags |= FC_ABORT;
4161a9b579f3SBram Moolenaar p += 5;
4162a9b579f3SBram Moolenaar }
416310ce39a0SBram Moolenaar else if (STRNCMP(p, "closure", 7) == 0)
416410ce39a0SBram Moolenaar {
416510ce39a0SBram Moolenaar flags |= FC_CLOSURE;
416610ce39a0SBram Moolenaar p += 7;
416758016448SBram Moolenaar if (current_funccal == NULL)
416858016448SBram Moolenaar {
4169ba209903SBram Moolenaar emsg_funcname(N_("E932: Closure function should not be at top level: %s"),
417058016448SBram Moolenaar name == NULL ? (char_u *)"" : name);
417158016448SBram Moolenaar goto erret;
417258016448SBram Moolenaar }
417310ce39a0SBram Moolenaar }
4174a9b579f3SBram Moolenaar else
4175a9b579f3SBram Moolenaar break;
4176a9b579f3SBram Moolenaar }
4177a9b579f3SBram Moolenaar
4178e38eab22SBram Moolenaar // When there is a line break use what follows for the function body.
4179e38eab22SBram Moolenaar // Makes 'exe "func Test()\n...\nendfunc"' work.
4180a9b579f3SBram Moolenaar if (*p == '\n')
4181a9b579f3SBram Moolenaar line_arg = p + 1;
4182e7e4838fSBram Moolenaar else if (*p != NUL
41839898107fSBram Moolenaar && !(*p == '"' && (!vim9script || eap->cmdidx == CMD_function)
41849898107fSBram Moolenaar && eap->cmdidx != CMD_def)
4185cef1270dSBram Moolenaar && !(VIM_ISWHITE(*whitep) && *p == '#'
4186cef1270dSBram Moolenaar && (vim9script || eap->cmdidx == CMD_def))
4187e7e4838fSBram Moolenaar && !eap->skip
4188e7e4838fSBram Moolenaar && !did_emsg)
41892d06bfdeSBram Moolenaar semsg(_(e_trailing_arg), p);
4190a9b579f3SBram Moolenaar
4191a9b579f3SBram Moolenaar /*
41928a7d6542SBram Moolenaar * Read the body of the function, until "}", ":endfunction" or ":enddef" is
41938a7d6542SBram Moolenaar * found.
4194a9b579f3SBram Moolenaar */
4195a9b579f3SBram Moolenaar if (KeyTyped)
4196a9b579f3SBram Moolenaar {
4197e38eab22SBram Moolenaar // Check if the function already exists, don't let the user type the
4198e38eab22SBram Moolenaar // whole function before telling him it doesn't work! For a script we
4199e38eab22SBram Moolenaar // need to skip the body to be able to find what follows.
4200a9b579f3SBram Moolenaar if (!eap->skip && !eap->forceit)
4201a9b579f3SBram Moolenaar {
4202a9b579f3SBram Moolenaar if (fudi.fd_dict != NULL && fudi.fd_newkey == NULL)
4203f9e3e09fSBram Moolenaar emsg(_(e_funcdict));
42044c17ad94SBram Moolenaar else if (name != NULL && find_func(name, is_global, NULL) != NULL)
4205a9b579f3SBram Moolenaar emsg_funcname(e_funcexts, name);
4206a9b579f3SBram Moolenaar }
4207a9b579f3SBram Moolenaar
4208a9b579f3SBram Moolenaar if (!eap->skip && did_emsg)
4209a9b579f3SBram Moolenaar goto erret;
4210a9b579f3SBram Moolenaar
4211e38eab22SBram Moolenaar msg_putchar('\n'); // don't overwrite the function name
4212a9b579f3SBram Moolenaar cmdline_row = msg_row;
4213a9b579f3SBram Moolenaar }
4214a9b579f3SBram Moolenaar
4215bc2cfe46SBram Moolenaar // Save the starting line number.
42161a47ae32SBram Moolenaar sourcing_lnum_top = SOURCING_LNUM;
4217bc2cfe46SBram Moolenaar
4218d87c21a9SBram Moolenaar // Do not define the function when getting the body fails and when
4219d87c21a9SBram Moolenaar // skipping.
4220d87c21a9SBram Moolenaar if (get_function_body(eap, &newlines, line_arg, &line_to_free) == FAIL
4221d87c21a9SBram Moolenaar || eap->skip)
4222a9b579f3SBram Moolenaar goto erret;
4223a9b579f3SBram Moolenaar
4224a9b579f3SBram Moolenaar /*
4225a9b579f3SBram Moolenaar * If there are no errors, add the function
4226a9b579f3SBram Moolenaar */
4227a9b579f3SBram Moolenaar if (fudi.fd_dict == NULL)
4228a9b579f3SBram Moolenaar {
42298a7d6542SBram Moolenaar hashtab_T *ht;
42308a7d6542SBram Moolenaar
423132b3f820SBram Moolenaar v = find_var(name, &ht, TRUE);
4232a9b579f3SBram Moolenaar if (v != NULL && v->di_tv.v_type == VAR_FUNC)
4233a9b579f3SBram Moolenaar {
4234a9b579f3SBram Moolenaar emsg_funcname(N_("E707: Function name conflicts with variable: %s"),
4235a9b579f3SBram Moolenaar name);
4236a9b579f3SBram Moolenaar goto erret;
4237a9b579f3SBram Moolenaar }
4238a9b579f3SBram Moolenaar
42394c17ad94SBram Moolenaar fp = find_func_even_dead(name, is_global, NULL);
4240eef2102eSBram Moolenaar if (vim9script)
4241a9b579f3SBram Moolenaar {
4242eef2102eSBram Moolenaar char_u *uname = untrans_function_name(name);
4243eef2102eSBram Moolenaar
4244eef2102eSBram Moolenaar import = find_imported(uname == NULL ? name : uname, 0, NULL);
4245eef2102eSBram Moolenaar }
4246eef2102eSBram Moolenaar
4247eef2102eSBram Moolenaar if (fp != NULL || import != NULL)
4248eef2102eSBram Moolenaar {
4249eef2102eSBram Moolenaar int dead = fp != NULL && (fp->uf_flags & FC_DEAD);
42508a7d6542SBram Moolenaar
4251ded5f1beSBram Moolenaar // Function can be replaced with "function!" and when sourcing the
4252ded5f1beSBram Moolenaar // same script again, but only once.
4253eef2102eSBram Moolenaar // A name that is used by an import can not be overruled.
4254eef2102eSBram Moolenaar if (import != NULL
4255eef2102eSBram Moolenaar || (!dead && !eap->forceit
4256ded5f1beSBram Moolenaar && (fp->uf_script_ctx.sc_sid != current_sctx.sc_sid
4257eef2102eSBram Moolenaar || fp->uf_script_ctx.sc_seq == current_sctx.sc_seq)))
4258a9b579f3SBram Moolenaar {
4259*d604d78eSBram Moolenaar SOURCING_LNUM = sourcing_lnum_top;
4260eef2102eSBram Moolenaar if (vim9script)
42617cb6fc29SBram Moolenaar emsg_funcname(e_name_already_defined_str, name);
4262eef2102eSBram Moolenaar else
4263a9b579f3SBram Moolenaar emsg_funcname(e_funcexts, name);
4264a9b579f3SBram Moolenaar goto erret;
4265a9b579f3SBram Moolenaar }
4266a9b579f3SBram Moolenaar if (fp->uf_calls > 0)
4267a9b579f3SBram Moolenaar {
4268ded5f1beSBram Moolenaar emsg_funcname(
4269ded5f1beSBram Moolenaar N_("E127: Cannot redefine function %s: It is in use"),
4270a9b579f3SBram Moolenaar name);
4271a9b579f3SBram Moolenaar goto erret;
4272a9b579f3SBram Moolenaar }
4273437bafe4SBram Moolenaar if (fp->uf_refcount > 1)
4274437bafe4SBram Moolenaar {
4275e38eab22SBram Moolenaar // This function is referenced somewhere, don't redefine it but
4276e38eab22SBram Moolenaar // create a new one.
4277437bafe4SBram Moolenaar --fp->uf_refcount;
42788dd3a43dSBram Moolenaar fp->uf_flags |= FC_REMOVED;
4279437bafe4SBram Moolenaar fp = NULL;
4280437bafe4SBram Moolenaar overwrite = TRUE;
4281437bafe4SBram Moolenaar }
4282437bafe4SBram Moolenaar else
4283437bafe4SBram Moolenaar {
4284b9adef79SBram Moolenaar char_u *exp_name = fp->uf_name_exp;
4285b9adef79SBram Moolenaar
4286b9adef79SBram Moolenaar // redefine existing function, keep the expanded name
4287d23a8236SBram Moolenaar VIM_CLEAR(name);
4288b9adef79SBram Moolenaar fp->uf_name_exp = NULL;
428979c2ad50SBram Moolenaar func_clear_items(fp);
4290b9adef79SBram Moolenaar fp->uf_name_exp = exp_name;
42918a7d6542SBram Moolenaar fp->uf_flags &= ~FC_DEAD;
429279c2ad50SBram Moolenaar #ifdef FEAT_PROFILE
429379c2ad50SBram Moolenaar fp->uf_profiling = FALSE;
429479c2ad50SBram Moolenaar fp->uf_prof_initialized = FALSE;
429579c2ad50SBram Moolenaar #endif
4296cdc40c43SBram Moolenaar fp->uf_def_status = UF_NOT_COMPILED;
4297a9b579f3SBram Moolenaar }
4298a9b579f3SBram Moolenaar }
4299437bafe4SBram Moolenaar }
4300a9b579f3SBram Moolenaar else
4301a9b579f3SBram Moolenaar {
4302a9b579f3SBram Moolenaar char numbuf[20];
4303a9b579f3SBram Moolenaar
4304a9b579f3SBram Moolenaar fp = NULL;
4305a9b579f3SBram Moolenaar if (fudi.fd_newkey == NULL && !eap->forceit)
4306a9b579f3SBram Moolenaar {
4307f9e3e09fSBram Moolenaar emsg(_(e_funcdict));
4308a9b579f3SBram Moolenaar goto erret;
4309a9b579f3SBram Moolenaar }
4310a9b579f3SBram Moolenaar if (fudi.fd_di == NULL)
4311a9b579f3SBram Moolenaar {
4312e38eab22SBram Moolenaar // Can't add a function to a locked dictionary
4313a187c43cSBram Moolenaar if (value_check_lock(fudi.fd_dict->dv_lock, eap->arg, FALSE))
4314a9b579f3SBram Moolenaar goto erret;
4315a9b579f3SBram Moolenaar }
4316e38eab22SBram Moolenaar // Can't change an existing function if it is locked
4317a187c43cSBram Moolenaar else if (value_check_lock(fudi.fd_di->di_tv.v_lock, eap->arg, FALSE))
4318a9b579f3SBram Moolenaar goto erret;
4319a9b579f3SBram Moolenaar
4320e38eab22SBram Moolenaar // Give the function a sequential number. Can only be used with a
4321e38eab22SBram Moolenaar // Funcref!
4322a9b579f3SBram Moolenaar vim_free(name);
4323a9b579f3SBram Moolenaar sprintf(numbuf, "%d", ++func_nr);
4324a9b579f3SBram Moolenaar name = vim_strsave((char_u *)numbuf);
4325a9b579f3SBram Moolenaar if (name == NULL)
4326a9b579f3SBram Moolenaar goto erret;
4327a9b579f3SBram Moolenaar }
4328a9b579f3SBram Moolenaar
4329a9b579f3SBram Moolenaar if (fp == NULL)
4330a9b579f3SBram Moolenaar {
4331a9b579f3SBram Moolenaar if (fudi.fd_dict == NULL && vim_strchr(name, AUTOLOAD_CHAR) != NULL)
4332a9b579f3SBram Moolenaar {
4333a9b579f3SBram Moolenaar int slen, plen;
4334a9b579f3SBram Moolenaar char_u *scriptname;
4335a9b579f3SBram Moolenaar
4336e38eab22SBram Moolenaar // Check that the autoload name matches the script name.
4337a9b579f3SBram Moolenaar j = FAIL;
43381a47ae32SBram Moolenaar if (SOURCING_NAME != NULL)
4339a9b579f3SBram Moolenaar {
4340a9b579f3SBram Moolenaar scriptname = autoload_name(name);
4341a9b579f3SBram Moolenaar if (scriptname != NULL)
4342a9b579f3SBram Moolenaar {
4343a9b579f3SBram Moolenaar p = vim_strchr(scriptname, '/');
4344a9b579f3SBram Moolenaar plen = (int)STRLEN(p);
43451a47ae32SBram Moolenaar slen = (int)STRLEN(SOURCING_NAME);
4346a9b579f3SBram Moolenaar if (slen > plen && fnamecmp(p,
43471a47ae32SBram Moolenaar SOURCING_NAME + slen - plen) == 0)
4348a9b579f3SBram Moolenaar j = OK;
4349a9b579f3SBram Moolenaar vim_free(scriptname);
4350a9b579f3SBram Moolenaar }
4351a9b579f3SBram Moolenaar }
4352a9b579f3SBram Moolenaar if (j == FAIL)
4353a9b579f3SBram Moolenaar {
4354f48b2fa3SBram Moolenaar linenr_T save_lnum = SOURCING_LNUM;
4355f48b2fa3SBram Moolenaar
4356f48b2fa3SBram Moolenaar SOURCING_LNUM = sourcing_lnum_top;
4357f9e3e09fSBram Moolenaar semsg(_("E746: Function name does not match script file name: %s"), name);
4358f48b2fa3SBram Moolenaar SOURCING_LNUM = save_lnum;
4359a9b579f3SBram Moolenaar goto erret;
4360a9b579f3SBram Moolenaar }
4361a9b579f3SBram Moolenaar }
4362a9b579f3SBram Moolenaar
436347ed553fSBram Moolenaar fp = alloc_clear(offsetof(ufunc_T, uf_name) + STRLEN(name) + 1);
4364a9b579f3SBram Moolenaar if (fp == NULL)
4365a9b579f3SBram Moolenaar goto erret;
4366a9b579f3SBram Moolenaar
4367a9b579f3SBram Moolenaar if (fudi.fd_dict != NULL)
4368a9b579f3SBram Moolenaar {
4369a9b579f3SBram Moolenaar if (fudi.fd_di == NULL)
4370a9b579f3SBram Moolenaar {
4371e38eab22SBram Moolenaar // add new dict entry
4372a9b579f3SBram Moolenaar fudi.fd_di = dictitem_alloc(fudi.fd_newkey);
4373a9b579f3SBram Moolenaar if (fudi.fd_di == NULL)
4374a9b579f3SBram Moolenaar {
4375a9b579f3SBram Moolenaar vim_free(fp);
4376a14e6975SBram Moolenaar fp = NULL;
4377a9b579f3SBram Moolenaar goto erret;
4378a9b579f3SBram Moolenaar }
4379a9b579f3SBram Moolenaar if (dict_add(fudi.fd_dict, fudi.fd_di) == FAIL)
4380a9b579f3SBram Moolenaar {
4381a9b579f3SBram Moolenaar vim_free(fudi.fd_di);
4382a9b579f3SBram Moolenaar vim_free(fp);
4383a14e6975SBram Moolenaar fp = NULL;
4384a9b579f3SBram Moolenaar goto erret;
4385a9b579f3SBram Moolenaar }
4386a9b579f3SBram Moolenaar }
4387a9b579f3SBram Moolenaar else
4388e38eab22SBram Moolenaar // overwrite existing dict entry
4389a9b579f3SBram Moolenaar clear_tv(&fudi.fd_di->di_tv);
4390a9b579f3SBram Moolenaar fudi.fd_di->di_tv.v_type = VAR_FUNC;
4391a9b579f3SBram Moolenaar fudi.fd_di->di_tv.vval.v_string = vim_strsave(name);
4392a9b579f3SBram Moolenaar
4393e38eab22SBram Moolenaar // behave like "dict" was used
4394a9b579f3SBram Moolenaar flags |= FC_DICT;
4395a9b579f3SBram Moolenaar }
4396a9b579f3SBram Moolenaar
4397e38eab22SBram Moolenaar // insert the new function in the function list
43981a47ae32SBram Moolenaar set_ufunc_name(fp, name);
4399437bafe4SBram Moolenaar if (overwrite)
4400437bafe4SBram Moolenaar {
4401437bafe4SBram Moolenaar hi = hash_find(&func_hashtab, name);
4402437bafe4SBram Moolenaar hi->hi_key = UF2HIKEY(fp);
4403437bafe4SBram Moolenaar }
4404437bafe4SBram Moolenaar else if (hash_add(&func_hashtab, UF2HIKEY(fp)) == FAIL)
4405a9b579f3SBram Moolenaar {
4406a9b579f3SBram Moolenaar vim_free(fp);
4407a14e6975SBram Moolenaar fp = NULL;
4408a9b579f3SBram Moolenaar goto erret;
4409a9b579f3SBram Moolenaar }
4410437bafe4SBram Moolenaar fp->uf_refcount = 1;
4411a9b579f3SBram Moolenaar }
4412a9b579f3SBram Moolenaar fp->uf_args = newargs;
441342ae78cfSBram Moolenaar fp->uf_def_args = default_args;
44148a7d6542SBram Moolenaar fp->uf_ret_type = &t_any;
44155deeb3f1SBram Moolenaar fp->uf_func_type = &t_func_any;
44168a7d6542SBram Moolenaar
44178a7d6542SBram Moolenaar if (eap->cmdidx == CMD_def)
44188a7d6542SBram Moolenaar {
4419bfe12043SBram Moolenaar int lnum_save = SOURCING_LNUM;
442039ca4127SBram Moolenaar cstack_T *cstack = eap->cstack;
4421bfe12043SBram Moolenaar
44220cb5bcf5SBram Moolenaar fp->uf_def_status = UF_TO_BE_COMPILED;
4423822ba247SBram Moolenaar
4424bfe12043SBram Moolenaar // error messages are for the first function line
4425bfe12043SBram Moolenaar SOURCING_LNUM = sourcing_lnum_top;
4426bfe12043SBram Moolenaar
44272eb6fc3bSBram Moolenaar // The function may use script variables from the context.
44282eb6fc3bSBram Moolenaar function_using_block_scopes(fp, cstack);
4429fbbcd003SBram Moolenaar
4430b4d16cb1SBram Moolenaar if (parse_argument_types(fp, &argtypes, varargs) == FAIL)
4431bfe12043SBram Moolenaar {
4432bfe12043SBram Moolenaar SOURCING_LNUM = lnum_save;
4433bfe12043SBram Moolenaar goto errret_2;
4434bfe12043SBram Moolenaar }
44358a7d6542SBram Moolenaar varargs = FALSE;
44368a7d6542SBram Moolenaar
44378a7d6542SBram Moolenaar // parse the return type, if any
44387a6eaa06SBram Moolenaar if (parse_return_type(fp, ret_type) == FAIL)
44398a7d6542SBram Moolenaar {
4440648ea76eSBram Moolenaar SOURCING_LNUM = lnum_save;
4441648ea76eSBram Moolenaar goto erret;
4442648ea76eSBram Moolenaar }
444309689a02SBram Moolenaar SOURCING_LNUM = lnum_save;
44448a7d6542SBram Moolenaar }
4445822ba247SBram Moolenaar else
44460cb5bcf5SBram Moolenaar fp->uf_def_status = UF_NOT_COMPILED;
44478a7d6542SBram Moolenaar
4448a9b579f3SBram Moolenaar fp->uf_lines = newlines;
444910ce39a0SBram Moolenaar if ((flags & FC_CLOSURE) != 0)
445010ce39a0SBram Moolenaar {
445158016448SBram Moolenaar if (register_closure(fp) == FAIL)
445210ce39a0SBram Moolenaar goto erret;
445310ce39a0SBram Moolenaar }
445410ce39a0SBram Moolenaar else
44551e96d9bfSBram Moolenaar fp->uf_scoped = NULL;
445610ce39a0SBram Moolenaar
4457a9b579f3SBram Moolenaar #ifdef FEAT_PROFILE
4458a9b579f3SBram Moolenaar if (prof_def_func())
4459a9b579f3SBram Moolenaar func_do_profile(fp);
4460a9b579f3SBram Moolenaar #endif
4461a9b579f3SBram Moolenaar fp->uf_varargs = varargs;
446293343725SBram Moolenaar if (sandbox)
446393343725SBram Moolenaar flags |= FC_SANDBOX;
4464e7e4838fSBram Moolenaar if (vim9script && !ASCII_ISUPPER(*fp->uf_name))
44654c17ad94SBram Moolenaar flags |= FC_VIM9;
4466a9b579f3SBram Moolenaar fp->uf_flags = flags;
4467a9b579f3SBram Moolenaar fp->uf_calls = 0;
446863ce4849SBram Moolenaar fp->uf_cleared = FALSE;
4469f29c1c6aSBram Moolenaar fp->uf_script_ctx = current_sctx;
4470f9b2b496SBram Moolenaar fp->uf_script_ctx_version = current_sctx.sc_version;
4471bc2cfe46SBram Moolenaar fp->uf_script_ctx.sc_lnum += sourcing_lnum_top;
44728a7d6542SBram Moolenaar if (is_export)
44738a7d6542SBram Moolenaar {
44748a7d6542SBram Moolenaar fp->uf_flags |= FC_EXPORT;
44758a7d6542SBram Moolenaar // let ex_export() know the export worked.
44768a7d6542SBram Moolenaar is_export = FALSE;
44778a7d6542SBram Moolenaar }
44788a7d6542SBram Moolenaar
44796ff71d8bSBram Moolenaar if (eap->cmdidx == CMD_def)
44806ff71d8bSBram Moolenaar set_function_type(fp);
44816797966dSBram Moolenaar else if (fp->uf_script_ctx.sc_version == SCRIPT_VERSION_VIM9)
44826797966dSBram Moolenaar // :func does not use Vim9 script syntax, even in a Vim9 script file
44836797966dSBram Moolenaar fp->uf_script_ctx.sc_version = SCRIPT_VERSION_MAX;
44846ff71d8bSBram Moolenaar
4485a9b579f3SBram Moolenaar goto ret_free;
4486a9b579f3SBram Moolenaar
4487a9b579f3SBram Moolenaar erret:
4488a9b579f3SBram Moolenaar ga_clear_strings(&newargs);
448942ae78cfSBram Moolenaar ga_clear_strings(&default_args);
449031842cd0SBram Moolenaar if (fp != NULL)
449131842cd0SBram Moolenaar {
449231842cd0SBram Moolenaar ga_init(&fp->uf_args);
449331842cd0SBram Moolenaar ga_init(&fp->uf_def_args);
449431842cd0SBram Moolenaar }
4495a9b579f3SBram Moolenaar errret_2:
4496a9b579f3SBram Moolenaar ga_clear_strings(&newlines);
449731842cd0SBram Moolenaar if (fp != NULL)
449831842cd0SBram Moolenaar VIM_CLEAR(fp->uf_arg_types);
4499a9b579f3SBram Moolenaar ret_free:
4500292b90d4SBram Moolenaar ga_clear_strings(&argtypes);
450153564f7cSBram Moolenaar vim_free(line_to_free);
4502a9b579f3SBram Moolenaar vim_free(fudi.fd_newkey);
450304b12697SBram Moolenaar if (name != name_arg)
4504a9b579f3SBram Moolenaar vim_free(name);
45055e774c75SBram Moolenaar vim_free(ret_type);
4506a9b579f3SBram Moolenaar did_emsg |= saved_did_emsg;
450704b12697SBram Moolenaar
450804b12697SBram Moolenaar return fp;
450904b12697SBram Moolenaar }
451004b12697SBram Moolenaar
451104b12697SBram Moolenaar /*
451204b12697SBram Moolenaar * ":function"
451304b12697SBram Moolenaar */
451404b12697SBram Moolenaar void
ex_function(exarg_T * eap)451504b12697SBram Moolenaar ex_function(exarg_T *eap)
451604b12697SBram Moolenaar {
4517fbbcd003SBram Moolenaar (void)define_function(eap, NULL);
4518822ba247SBram Moolenaar }
4519822ba247SBram Moolenaar
4520822ba247SBram Moolenaar /*
452196f8f499SBram Moolenaar * :defcompile - compile all :def functions in the current script that need to
4522b2049903SBram Moolenaar * be compiled. Except dead functions. Doesn't do profiling.
4523822ba247SBram Moolenaar */
4524822ba247SBram Moolenaar void
ex_defcompile(exarg_T * eap UNUSED)4525822ba247SBram Moolenaar ex_defcompile(exarg_T *eap UNUSED)
4526822ba247SBram Moolenaar {
45277ce85be6SBram Moolenaar long todo = (long)func_hashtab.ht_used;
45287ce85be6SBram Moolenaar int changed = func_hashtab.ht_changed;
4529822ba247SBram Moolenaar hashitem_T *hi;
4530822ba247SBram Moolenaar ufunc_T *ufunc;
4531822ba247SBram Moolenaar
4532822ba247SBram Moolenaar for (hi = func_hashtab.ht_array; todo > 0 && !got_int; ++hi)
4533822ba247SBram Moolenaar {
4534822ba247SBram Moolenaar if (!HASHITEM_EMPTY(hi))
4535822ba247SBram Moolenaar {
4536822ba247SBram Moolenaar --todo;
4537822ba247SBram Moolenaar ufunc = HI2UF(hi);
4538822ba247SBram Moolenaar if (ufunc->uf_script_ctx.sc_sid == current_sctx.sc_sid
453996f8f499SBram Moolenaar && ufunc->uf_def_status == UF_TO_BE_COMPILED
454096f8f499SBram Moolenaar && (ufunc->uf_flags & FC_DEAD) == 0)
4541ebc3de63SBram Moolenaar {
4542e99d422bSBram Moolenaar (void)compile_def_function(ufunc, FALSE, CT_NONE, NULL);
4543ebc3de63SBram Moolenaar
45447ce85be6SBram Moolenaar if (func_hashtab.ht_changed != changed)
4545ebc3de63SBram Moolenaar {
45467ce85be6SBram Moolenaar // a function has been added or removed, need to start over
45477ce85be6SBram Moolenaar todo = (long)func_hashtab.ht_used;
45487ce85be6SBram Moolenaar changed = func_hashtab.ht_changed;
4549ebc3de63SBram Moolenaar hi = func_hashtab.ht_array;
4550285b1892SBram Moolenaar --hi;
4551ebc3de63SBram Moolenaar }
4552ebc3de63SBram Moolenaar }
4553822ba247SBram Moolenaar }
4554822ba247SBram Moolenaar }
4555a9b579f3SBram Moolenaar }
4556a9b579f3SBram Moolenaar
4557a9b579f3SBram Moolenaar /*
4558a9b579f3SBram Moolenaar * Return 5 if "p" starts with "<SID>" or "<SNR>" (ignoring case).
4559a9b579f3SBram Moolenaar * Return 2 if "p" starts with "s:".
4560a9b579f3SBram Moolenaar * Return 0 otherwise.
4561a9b579f3SBram Moolenaar */
4562a9b579f3SBram Moolenaar int
eval_fname_script(char_u * p)4563a9b579f3SBram Moolenaar eval_fname_script(char_u *p)
4564a9b579f3SBram Moolenaar {
4565e38eab22SBram Moolenaar // Use MB_STRICMP() because in Turkish comparing the "I" may not work with
4566e38eab22SBram Moolenaar // the standard library function.
4567a9b579f3SBram Moolenaar if (p[0] == '<' && (MB_STRNICMP(p + 1, "SID>", 4) == 0
4568a9b579f3SBram Moolenaar || MB_STRNICMP(p + 1, "SNR>", 4) == 0))
4569a9b579f3SBram Moolenaar return 5;
4570a9b579f3SBram Moolenaar if (p[0] == 's' && p[1] == ':')
4571a9b579f3SBram Moolenaar return 2;
4572a9b579f3SBram Moolenaar return 0;
4573a9b579f3SBram Moolenaar }
4574a9b579f3SBram Moolenaar
4575a9b579f3SBram Moolenaar int
translated_function_exists(char_u * name,int is_global)45764c17ad94SBram Moolenaar translated_function_exists(char_u *name, int is_global)
4577a9b579f3SBram Moolenaar {
4578a9b579f3SBram Moolenaar if (builtin_function(name, -1))
4579ac92e25aSBram Moolenaar return has_internal_func(name);
45804c17ad94SBram Moolenaar return find_func(name, is_global, NULL) != NULL;
45818a7d6542SBram Moolenaar }
45828a7d6542SBram Moolenaar
45838a7d6542SBram Moolenaar /*
45848a7d6542SBram Moolenaar * Return TRUE when "ufunc" has old-style "..." varargs
45858a7d6542SBram Moolenaar * or named varargs "...name: type".
45868a7d6542SBram Moolenaar */
45878a7d6542SBram Moolenaar int
has_varargs(ufunc_T * ufunc)45888a7d6542SBram Moolenaar has_varargs(ufunc_T *ufunc)
45898a7d6542SBram Moolenaar {
45908a7d6542SBram Moolenaar return ufunc->uf_varargs || ufunc->uf_va_name != NULL;
4591a9b579f3SBram Moolenaar }
4592a9b579f3SBram Moolenaar
4593a9b579f3SBram Moolenaar /*
4594a9b579f3SBram Moolenaar * Return TRUE if a function "name" exists.
4595b54c3ff3SBram Moolenaar * If "no_defef" is TRUE, do not dereference a Funcref.
4596a9b579f3SBram Moolenaar */
4597a9b579f3SBram Moolenaar int
function_exists(char_u * name,int no_deref)4598b54c3ff3SBram Moolenaar function_exists(char_u *name, int no_deref)
4599a9b579f3SBram Moolenaar {
4600a9b579f3SBram Moolenaar char_u *nm = name;
4601a9b579f3SBram Moolenaar char_u *p;
4602a9b579f3SBram Moolenaar int n = FALSE;
4603b54c3ff3SBram Moolenaar int flag;
46044c17ad94SBram Moolenaar int is_global = FALSE;
4605a9b579f3SBram Moolenaar
4606b54c3ff3SBram Moolenaar flag = TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD;
4607b54c3ff3SBram Moolenaar if (no_deref)
4608b54c3ff3SBram Moolenaar flag |= TFN_NO_DEREF;
460932b3f820SBram Moolenaar p = trans_function_name(&nm, &is_global, FALSE, flag, NULL, NULL, NULL);
4610a9b579f3SBram Moolenaar nm = skipwhite(nm);
4611a9b579f3SBram Moolenaar
4612e38eab22SBram Moolenaar // Only accept "funcname", "funcname ", "funcname (..." and
4613e38eab22SBram Moolenaar // "funcname(...", not "funcname!...".
4614a9b579f3SBram Moolenaar if (p != NULL && (*nm == NUL || *nm == '('))
46154c17ad94SBram Moolenaar n = translated_function_exists(p, is_global);
4616a9b579f3SBram Moolenaar vim_free(p);
4617a9b579f3SBram Moolenaar return n;
4618a9b579f3SBram Moolenaar }
4619a9b579f3SBram Moolenaar
4620113e1072SBram Moolenaar #if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3) || defined(PROTO)
4621a9b579f3SBram Moolenaar char_u *
get_expanded_name(char_u * name,int check)4622a9b579f3SBram Moolenaar get_expanded_name(char_u *name, int check)
4623a9b579f3SBram Moolenaar {
4624a9b579f3SBram Moolenaar char_u *nm = name;
4625a9b579f3SBram Moolenaar char_u *p;
46264c17ad94SBram Moolenaar int is_global = FALSE;
4627a9b579f3SBram Moolenaar
46284c17ad94SBram Moolenaar p = trans_function_name(&nm, &is_global, FALSE,
462932b3f820SBram Moolenaar TFN_INT|TFN_QUIET, NULL, NULL, NULL);
4630a9b579f3SBram Moolenaar
46314c17ad94SBram Moolenaar if (p != NULL && *nm == NUL
46324c17ad94SBram Moolenaar && (!check || translated_function_exists(p, is_global)))
4633a9b579f3SBram Moolenaar return p;
4634a9b579f3SBram Moolenaar
4635a9b579f3SBram Moolenaar vim_free(p);
4636a9b579f3SBram Moolenaar return NULL;
4637a9b579f3SBram Moolenaar }
4638113e1072SBram Moolenaar #endif
4639a9b579f3SBram Moolenaar
4640a9b579f3SBram Moolenaar /*
4641a9b579f3SBram Moolenaar * Function given to ExpandGeneric() to obtain the list of user defined
4642a9b579f3SBram Moolenaar * function names.
4643a9b579f3SBram Moolenaar */
4644a9b579f3SBram Moolenaar char_u *
get_user_func_name(expand_T * xp,int idx)4645a9b579f3SBram Moolenaar get_user_func_name(expand_T *xp, int idx)
4646a9b579f3SBram Moolenaar {
4647a9b579f3SBram Moolenaar static long_u done;
46481f22cc5cSBram Moolenaar static int changed;
4649a9b579f3SBram Moolenaar static hashitem_T *hi;
4650a9b579f3SBram Moolenaar ufunc_T *fp;
4651a9b579f3SBram Moolenaar
4652a9b579f3SBram Moolenaar if (idx == 0)
4653a9b579f3SBram Moolenaar {
4654a9b579f3SBram Moolenaar done = 0;
4655a9b579f3SBram Moolenaar hi = func_hashtab.ht_array;
46561f22cc5cSBram Moolenaar changed = func_hashtab.ht_changed;
4657a9b579f3SBram Moolenaar }
46581f22cc5cSBram Moolenaar if (changed == func_hashtab.ht_changed && done < func_hashtab.ht_used)
4659a9b579f3SBram Moolenaar {
4660a9b579f3SBram Moolenaar if (done++ > 0)
4661a9b579f3SBram Moolenaar ++hi;
4662a9b579f3SBram Moolenaar while (HASHITEM_EMPTY(hi))
4663a9b579f3SBram Moolenaar ++hi;
4664a9b579f3SBram Moolenaar fp = HI2UF(hi);
4665a9b579f3SBram Moolenaar
46668a7d6542SBram Moolenaar // don't show dead, dict and lambda functions
46678a7d6542SBram Moolenaar if ((fp->uf_flags & FC_DEAD) || (fp->uf_flags & FC_DICT)
4668b49edc11SBram Moolenaar || STRNCMP(fp->uf_name, "<lambda>", 8) == 0)
46698a7d6542SBram Moolenaar return (char_u *)"";
4670a9b579f3SBram Moolenaar
4671a9b579f3SBram Moolenaar if (STRLEN(fp->uf_name) + 4 >= IOSIZE)
4672e38eab22SBram Moolenaar return fp->uf_name; // prevents overflow
4673a9b579f3SBram Moolenaar
4674a9b579f3SBram Moolenaar cat_func_name(IObuff, fp);
46759aecf79cSnaohiro ono if (xp->xp_context != EXPAND_USER_FUNC
46769aecf79cSnaohiro ono && xp->xp_context != EXPAND_DISASSEMBLE)
4677a9b579f3SBram Moolenaar {
4678a9b579f3SBram Moolenaar STRCAT(IObuff, "(");
46798a7d6542SBram Moolenaar if (!has_varargs(fp) && fp->uf_args.ga_len == 0)
4680a9b579f3SBram Moolenaar STRCAT(IObuff, ")");
4681a9b579f3SBram Moolenaar }
4682a9b579f3SBram Moolenaar return IObuff;
4683a9b579f3SBram Moolenaar }
4684a9b579f3SBram Moolenaar return NULL;
4685a9b579f3SBram Moolenaar }
4686a9b579f3SBram Moolenaar
4687a9b579f3SBram Moolenaar /*
4688a9b579f3SBram Moolenaar * ":delfunction {name}"
4689a9b579f3SBram Moolenaar */
4690a9b579f3SBram Moolenaar void
ex_delfunction(exarg_T * eap)4691a9b579f3SBram Moolenaar ex_delfunction(exarg_T *eap)
4692a9b579f3SBram Moolenaar {
4693a9b579f3SBram Moolenaar ufunc_T *fp = NULL;
4694a9b579f3SBram Moolenaar char_u *p;
4695a9b579f3SBram Moolenaar char_u *name;
4696a9b579f3SBram Moolenaar funcdict_T fudi;
46974c17ad94SBram Moolenaar int is_global = FALSE;
4698a9b579f3SBram Moolenaar
4699a9b579f3SBram Moolenaar p = eap->arg;
470032b3f820SBram Moolenaar name = trans_function_name(&p, &is_global, eap->skip, 0, &fudi,
470132b3f820SBram Moolenaar NULL, NULL);
4702a9b579f3SBram Moolenaar vim_free(fudi.fd_newkey);
4703a9b579f3SBram Moolenaar if (name == NULL)
4704a9b579f3SBram Moolenaar {
4705a9b579f3SBram Moolenaar if (fudi.fd_dict != NULL && !eap->skip)
4706f9e3e09fSBram Moolenaar emsg(_(e_funcref));
4707a9b579f3SBram Moolenaar return;
4708a9b579f3SBram Moolenaar }
4709a9b579f3SBram Moolenaar if (!ends_excmd(*skipwhite(p)))
4710a9b579f3SBram Moolenaar {
4711a9b579f3SBram Moolenaar vim_free(name);
47122d06bfdeSBram Moolenaar semsg(_(e_trailing_arg), p);
4713a9b579f3SBram Moolenaar return;
4714a9b579f3SBram Moolenaar }
471563b91736SBram Moolenaar set_nextcmd(eap, p);
4716a9b579f3SBram Moolenaar if (eap->nextcmd != NULL)
4717a9b579f3SBram Moolenaar *p = NUL;
4718a9b579f3SBram Moolenaar
4719ddfc0510SBram Moolenaar if (isdigit(*name) && fudi.fd_dict == NULL)
4720ddfc0510SBram Moolenaar {
4721ddfc0510SBram Moolenaar if (!eap->skip)
4722ddfc0510SBram Moolenaar semsg(_(e_invarg2), eap->arg);
4723ddfc0510SBram Moolenaar vim_free(name);
4724ddfc0510SBram Moolenaar return;
4725ddfc0510SBram Moolenaar }
4726a9b579f3SBram Moolenaar if (!eap->skip)
47274c17ad94SBram Moolenaar fp = find_func(name, is_global, NULL);
4728a9b579f3SBram Moolenaar vim_free(name);
4729a9b579f3SBram Moolenaar
4730a9b579f3SBram Moolenaar if (!eap->skip)
4731a9b579f3SBram Moolenaar {
4732a9b579f3SBram Moolenaar if (fp == NULL)
4733a9b579f3SBram Moolenaar {
4734d6abcd15SBram Moolenaar if (!eap->forceit)
4735f9e3e09fSBram Moolenaar semsg(_(e_nofunc), eap->arg);
4736a9b579f3SBram Moolenaar return;
4737a9b579f3SBram Moolenaar }
4738a9b579f3SBram Moolenaar if (fp->uf_calls > 0)
4739a9b579f3SBram Moolenaar {
4740f9e3e09fSBram Moolenaar semsg(_("E131: Cannot delete function %s: It is in use"), eap->arg);
4741a9b579f3SBram Moolenaar return;
4742a9b579f3SBram Moolenaar }
47434c17ad94SBram Moolenaar if (fp->uf_flags & FC_VIM9)
47444c17ad94SBram Moolenaar {
4745451c2e35SBram Moolenaar semsg(_(e_cannot_delete_vim9_script_function_str), eap->arg);
47464c17ad94SBram Moolenaar return;
47474c17ad94SBram Moolenaar }
4748a9b579f3SBram Moolenaar
4749a9b579f3SBram Moolenaar if (fudi.fd_dict != NULL)
4750a9b579f3SBram Moolenaar {
4751e38eab22SBram Moolenaar // Delete the dict item that refers to the function, it will
4752e38eab22SBram Moolenaar // invoke func_unref() and possibly delete the function.
4753a9b579f3SBram Moolenaar dictitem_remove(fudi.fd_dict, fudi.fd_di);
4754a9b579f3SBram Moolenaar }
4755a9b579f3SBram Moolenaar else
4756437bafe4SBram Moolenaar {
4757e38eab22SBram Moolenaar // A normal function (not a numbered function or lambda) has a
4758e38eab22SBram Moolenaar // refcount of 1 for the entry in the hashtable. When deleting
4759e38eab22SBram Moolenaar // it and the refcount is more than one, it should be kept.
4760e38eab22SBram Moolenaar // A numbered function and lambda should be kept if the refcount is
4761e38eab22SBram Moolenaar // one or more.
47628dd3a43dSBram Moolenaar if (fp->uf_refcount > (func_name_refcount(fp->uf_name) ? 0 : 1))
4763437bafe4SBram Moolenaar {
4764e38eab22SBram Moolenaar // Function is still referenced somewhere. Don't free it but
4765e38eab22SBram Moolenaar // do remove it from the hashtable.
47668dd3a43dSBram Moolenaar if (func_remove(fp))
4767437bafe4SBram Moolenaar fp->uf_refcount--;
4768437bafe4SBram Moolenaar }
4769437bafe4SBram Moolenaar else
477003ff9bcbSBram Moolenaar func_clear_free(fp, FALSE);
4771a9b579f3SBram Moolenaar }
4772a9b579f3SBram Moolenaar }
4773437bafe4SBram Moolenaar }
4774a9b579f3SBram Moolenaar
4775a9b579f3SBram Moolenaar /*
4776a9b579f3SBram Moolenaar * Unreference a Function: decrement the reference count and free it when it
4777437bafe4SBram Moolenaar * becomes zero.
4778a9b579f3SBram Moolenaar */
4779a9b579f3SBram Moolenaar void
func_unref(char_u * name)4780a9b579f3SBram Moolenaar func_unref(char_u *name)
4781a9b579f3SBram Moolenaar {
478297baee80SBram Moolenaar ufunc_T *fp = NULL;
4783a9b579f3SBram Moolenaar
47848dd3a43dSBram Moolenaar if (name == NULL || !func_name_refcount(name))
4785a9b579f3SBram Moolenaar return;
47864c17ad94SBram Moolenaar fp = find_func(name, FALSE, NULL);
4787437bafe4SBram Moolenaar if (fp == NULL && isdigit(*name))
4788a9b579f3SBram Moolenaar {
4789a9b579f3SBram Moolenaar #ifdef EXITFREE
4790a9b579f3SBram Moolenaar if (!entered_free_all_mem)
4791a9b579f3SBram Moolenaar #endif
479295f09603SBram Moolenaar internal_error("func_unref()");
4793a9b579f3SBram Moolenaar }
47940d3de8cbSBram Moolenaar func_ptr_unref(fp);
4795437bafe4SBram Moolenaar }
4796437bafe4SBram Moolenaar
4797437bafe4SBram Moolenaar /*
4798437bafe4SBram Moolenaar * Unreference a Function: decrement the reference count and free it when it
4799437bafe4SBram Moolenaar * becomes zero.
48000d3de8cbSBram Moolenaar * Also when it becomes one and uf_partial points to the function.
4801437bafe4SBram Moolenaar */
4802437bafe4SBram Moolenaar void
func_ptr_unref(ufunc_T * fp)4803437bafe4SBram Moolenaar func_ptr_unref(ufunc_T *fp)
4804437bafe4SBram Moolenaar {
48050d3de8cbSBram Moolenaar if (fp != NULL && (--fp->uf_refcount <= 0
48060d3de8cbSBram Moolenaar || (fp->uf_refcount == 1 && fp->uf_partial != NULL
48070d3de8cbSBram Moolenaar && fp->uf_partial->pt_refcount <= 1
48080d3de8cbSBram Moolenaar && fp->uf_partial->pt_func == fp)))
4809a9b579f3SBram Moolenaar {
4810e38eab22SBram Moolenaar // Only delete it when it's not being used. Otherwise it's done
4811e38eab22SBram Moolenaar // when "uf_calls" becomes zero.
4812a9b579f3SBram Moolenaar if (fp->uf_calls == 0)
481303ff9bcbSBram Moolenaar func_clear_free(fp, FALSE);
4814a9b579f3SBram Moolenaar }
4815a9b579f3SBram Moolenaar }
4816a9b579f3SBram Moolenaar
4817a9b579f3SBram Moolenaar /*
4818a9b579f3SBram Moolenaar * Count a reference to a Function.
4819a9b579f3SBram Moolenaar */
4820a9b579f3SBram Moolenaar void
func_ref(char_u * name)4821a9b579f3SBram Moolenaar func_ref(char_u *name)
4822a9b579f3SBram Moolenaar {
4823a9b579f3SBram Moolenaar ufunc_T *fp;
4824a9b579f3SBram Moolenaar
48258dd3a43dSBram Moolenaar if (name == NULL || !func_name_refcount(name))
4826a9b579f3SBram Moolenaar return;
48274c17ad94SBram Moolenaar fp = find_func(name, FALSE, NULL);
4828a9b579f3SBram Moolenaar if (fp != NULL)
4829a9b579f3SBram Moolenaar ++fp->uf_refcount;
4830437bafe4SBram Moolenaar else if (isdigit(*name))
4831e38eab22SBram Moolenaar // Only give an error for a numbered function.
4832e38eab22SBram Moolenaar // Fail silently, when named or lambda function isn't found.
483395f09603SBram Moolenaar internal_error("func_ref()");
4834a9b579f3SBram Moolenaar }
4835437bafe4SBram Moolenaar
4836437bafe4SBram Moolenaar /*
4837437bafe4SBram Moolenaar * Count a reference to a Function.
4838437bafe4SBram Moolenaar */
4839437bafe4SBram Moolenaar void
func_ptr_ref(ufunc_T * fp)4840437bafe4SBram Moolenaar func_ptr_ref(ufunc_T *fp)
4841437bafe4SBram Moolenaar {
4842437bafe4SBram Moolenaar if (fp != NULL)
4843437bafe4SBram Moolenaar ++fp->uf_refcount;
4844a9b579f3SBram Moolenaar }
4845a9b579f3SBram Moolenaar
4846a9b579f3SBram Moolenaar /*
4847a9b579f3SBram Moolenaar * Return TRUE if items in "fc" do not have "copyID". That means they are not
4848a9b579f3SBram Moolenaar * referenced from anywhere that is in use.
4849a9b579f3SBram Moolenaar */
4850a9b579f3SBram Moolenaar static int
can_free_funccal(funccall_T * fc,int copyID)4851a9b579f3SBram Moolenaar can_free_funccal(funccall_T *fc, int copyID)
4852a9b579f3SBram Moolenaar {
4853a9b579f3SBram Moolenaar return (fc->l_varlist.lv_copyID != copyID
4854a9b579f3SBram Moolenaar && fc->l_vars.dv_copyID != copyID
48551e96d9bfSBram Moolenaar && fc->l_avars.dv_copyID != copyID
48561e96d9bfSBram Moolenaar && fc->fc_copyID != copyID);
4857a9b579f3SBram Moolenaar }
4858a9b579f3SBram Moolenaar
4859a9b579f3SBram Moolenaar /*
4860a9b579f3SBram Moolenaar * ":return [expr]"
4861a9b579f3SBram Moolenaar */
4862a9b579f3SBram Moolenaar void
ex_return(exarg_T * eap)4863a9b579f3SBram Moolenaar ex_return(exarg_T *eap)
4864a9b579f3SBram Moolenaar {
4865a9b579f3SBram Moolenaar char_u *arg = eap->arg;
4866a9b579f3SBram Moolenaar typval_T rettv;
4867a9b579f3SBram Moolenaar int returning = FALSE;
48685409f5d8SBram Moolenaar evalarg_T evalarg;
4869a9b579f3SBram Moolenaar
4870a9b579f3SBram Moolenaar if (current_funccal == NULL)
4871a9b579f3SBram Moolenaar {
4872f9e3e09fSBram Moolenaar emsg(_("E133: :return not inside a function"));
4873a9b579f3SBram Moolenaar return;
4874a9b579f3SBram Moolenaar }
4875a9b579f3SBram Moolenaar
4876844fb64aSBram Moolenaar init_evalarg(&evalarg);
48775409f5d8SBram Moolenaar evalarg.eval_flags = eap->skip ? 0 : EVAL_EVALUATE;
48785409f5d8SBram Moolenaar
4879a9b579f3SBram Moolenaar if (eap->skip)
4880a9b579f3SBram Moolenaar ++emsg_skip;
4881a9b579f3SBram Moolenaar
4882a9b579f3SBram Moolenaar eap->nextcmd = NULL;
4883a9b579f3SBram Moolenaar if ((*arg != NUL && *arg != '|' && *arg != '\n')
4884b171fb17SBram Moolenaar && eval0(arg, &rettv, eap, &evalarg) != FAIL)
4885a9b579f3SBram Moolenaar {
4886a9b579f3SBram Moolenaar if (!eap->skip)
4887a9b579f3SBram Moolenaar returning = do_return(eap, FALSE, TRUE, &rettv);
4888a9b579f3SBram Moolenaar else
4889a9b579f3SBram Moolenaar clear_tv(&rettv);
4890a9b579f3SBram Moolenaar }
4891e38eab22SBram Moolenaar // It's safer to return also on error.
4892a9b579f3SBram Moolenaar else if (!eap->skip)
4893a9b579f3SBram Moolenaar {
4894e38eab22SBram Moolenaar // In return statement, cause_abort should be force_abort.
4895fabaf753SBram Moolenaar update_force_abort();
4896fabaf753SBram Moolenaar
4897a9b579f3SBram Moolenaar /*
4898a9b579f3SBram Moolenaar * Return unless the expression evaluation has been cancelled due to an
4899a9b579f3SBram Moolenaar * aborting error, an interrupt, or an exception.
4900a9b579f3SBram Moolenaar */
4901a9b579f3SBram Moolenaar if (!aborting())
4902a9b579f3SBram Moolenaar returning = do_return(eap, FALSE, TRUE, NULL);
4903a9b579f3SBram Moolenaar }
4904a9b579f3SBram Moolenaar
4905e38eab22SBram Moolenaar // When skipping or the return gets pending, advance to the next command
4906e38eab22SBram Moolenaar // in this line (!returning). Otherwise, ignore the rest of the line.
4907e38eab22SBram Moolenaar // Following lines will be ignored by get_func_line().
4908a9b579f3SBram Moolenaar if (returning)
4909a9b579f3SBram Moolenaar eap->nextcmd = NULL;
4910e38eab22SBram Moolenaar else if (eap->nextcmd == NULL) // no argument
491163b91736SBram Moolenaar set_nextcmd(eap, arg);
4912a9b579f3SBram Moolenaar
4913a9b579f3SBram Moolenaar if (eap->skip)
4914a9b579f3SBram Moolenaar --emsg_skip;
4915b7a78f7aSBram Moolenaar clear_evalarg(&evalarg, eap);
4916a9b579f3SBram Moolenaar }
4917a9b579f3SBram Moolenaar
4918a9b579f3SBram Moolenaar /*
4919a9b579f3SBram Moolenaar * ":1,25call func(arg1, arg2)" function call.
4920a9b579f3SBram Moolenaar */
4921a9b579f3SBram Moolenaar void
ex_call(exarg_T * eap)4922a9b579f3SBram Moolenaar ex_call(exarg_T *eap)
4923a9b579f3SBram Moolenaar {
4924a9b579f3SBram Moolenaar char_u *arg = eap->arg;
4925a9b579f3SBram Moolenaar char_u *startarg;
4926a9b579f3SBram Moolenaar char_u *name;
4927a9b579f3SBram Moolenaar char_u *tofree;
4928a9b579f3SBram Moolenaar int len;
4929a9b579f3SBram Moolenaar typval_T rettv;
4930a9b579f3SBram Moolenaar linenr_T lnum;
4931a9b579f3SBram Moolenaar int doesrange;
4932a9b579f3SBram Moolenaar int failed = FALSE;
4933a9b579f3SBram Moolenaar funcdict_T fudi;
4934a9b579f3SBram Moolenaar partial_T *partial = NULL;
4935e6b5324eSBram Moolenaar evalarg_T evalarg;
493632b3f820SBram Moolenaar type_T *type = NULL;
4937a9b579f3SBram Moolenaar
4938e6b5324eSBram Moolenaar fill_evalarg_from_eap(&evalarg, eap, eap->skip);
4939a9b579f3SBram Moolenaar if (eap->skip)
4940a9b579f3SBram Moolenaar {
4941e38eab22SBram Moolenaar // trans_function_name() doesn't work well when skipping, use eval0()
4942e38eab22SBram Moolenaar // instead to skip to any following command, e.g. for:
4943e38eab22SBram Moolenaar // :if 0 | call dict.foo().bar() | endif
4944a9b579f3SBram Moolenaar ++emsg_skip;
4945e6b5324eSBram Moolenaar if (eval0(eap->arg, &rettv, eap, &evalarg) != FAIL)
4946a9b579f3SBram Moolenaar clear_tv(&rettv);
4947a9b579f3SBram Moolenaar --emsg_skip;
4948e6b5324eSBram Moolenaar clear_evalarg(&evalarg, eap);
4949a9b579f3SBram Moolenaar return;
4950a9b579f3SBram Moolenaar }
4951a9b579f3SBram Moolenaar
495232b3f820SBram Moolenaar tofree = trans_function_name(&arg, NULL, eap->skip, TFN_INT,
495332b3f820SBram Moolenaar &fudi, &partial, in_vim9script() ? &type : NULL);
4954a9b579f3SBram Moolenaar if (fudi.fd_newkey != NULL)
4955a9b579f3SBram Moolenaar {
4956e38eab22SBram Moolenaar // Still need to give an error message for missing key.
4957f9e3e09fSBram Moolenaar semsg(_(e_dictkey), fudi.fd_newkey);
4958a9b579f3SBram Moolenaar vim_free(fudi.fd_newkey);
4959a9b579f3SBram Moolenaar }
4960a9b579f3SBram Moolenaar if (tofree == NULL)
4961a9b579f3SBram Moolenaar return;
4962a9b579f3SBram Moolenaar
4963e38eab22SBram Moolenaar // Increase refcount on dictionary, it could get deleted when evaluating
4964e38eab22SBram Moolenaar // the arguments.
4965a9b579f3SBram Moolenaar if (fudi.fd_dict != NULL)
4966a9b579f3SBram Moolenaar ++fudi.fd_dict->dv_refcount;
4967a9b579f3SBram Moolenaar
4968e38eab22SBram Moolenaar // If it is the name of a variable of type VAR_FUNC or VAR_PARTIAL use its
4969e38eab22SBram Moolenaar // contents. For VAR_PARTIAL get its partial, unless we already have one
4970e38eab22SBram Moolenaar // from trans_function_name().
4971a9b579f3SBram Moolenaar len = (int)STRLEN(tofree);
497232b3f820SBram Moolenaar name = deref_func_name(tofree, &len, partial != NULL ? NULL : &partial,
497332b3f820SBram Moolenaar in_vim9script() && type == NULL ? &type : NULL, FALSE);
4974a9b579f3SBram Moolenaar
4975e38eab22SBram Moolenaar // Skip white space to allow ":call func ()". Not good, but required for
4976e38eab22SBram Moolenaar // backward compatibility.
4977a9b579f3SBram Moolenaar startarg = skipwhite(arg);
4978a9b579f3SBram Moolenaar if (*startarg != '(')
4979a9b579f3SBram Moolenaar {
49808a7d6542SBram Moolenaar semsg(_(e_missing_paren), eap->arg);
4981a9b579f3SBram Moolenaar goto end;
4982a9b579f3SBram Moolenaar }
498301dd6c37SBram Moolenaar if (in_vim9script() && startarg > arg)
498401dd6c37SBram Moolenaar {
498501dd6c37SBram Moolenaar semsg(_(e_no_white_space_allowed_before_str_str), "(", eap->arg);
498601dd6c37SBram Moolenaar goto end;
498701dd6c37SBram Moolenaar }
4988a9b579f3SBram Moolenaar
4989a9b579f3SBram Moolenaar /*
4990a9b579f3SBram Moolenaar * When skipping, evaluate the function once, to find the end of the
4991a9b579f3SBram Moolenaar * arguments.
4992a9b579f3SBram Moolenaar * When the function takes a range, this is discovered after the first
4993a9b579f3SBram Moolenaar * call, and the loop is broken.
4994a9b579f3SBram Moolenaar */
4995a9b579f3SBram Moolenaar if (eap->skip)
4996a9b579f3SBram Moolenaar {
4997a9b579f3SBram Moolenaar ++emsg_skip;
4998e38eab22SBram Moolenaar lnum = eap->line2; // do it once, also with an invalid range
4999a9b579f3SBram Moolenaar }
5000a9b579f3SBram Moolenaar else
5001a9b579f3SBram Moolenaar lnum = eap->line1;
5002a9b579f3SBram Moolenaar for ( ; lnum <= eap->line2; ++lnum)
5003a9b579f3SBram Moolenaar {
5004c6538bccSBram Moolenaar funcexe_T funcexe;
5005c6538bccSBram Moolenaar
5006a9b579f3SBram Moolenaar if (!eap->skip && eap->addr_count > 0)
5007a9b579f3SBram Moolenaar {
50089e353b52SBram Moolenaar if (lnum > curbuf->b_ml.ml_line_count)
50099e353b52SBram Moolenaar {
50109e353b52SBram Moolenaar // If the function deleted lines or switched to another buffer
50119e353b52SBram Moolenaar // the line number may become invalid.
5012108010aaSBram Moolenaar emsg(_(e_invalid_range));
50139e353b52SBram Moolenaar break;
50149e353b52SBram Moolenaar }
5015a9b579f3SBram Moolenaar curwin->w_cursor.lnum = lnum;
5016a9b579f3SBram Moolenaar curwin->w_cursor.col = 0;
5017a9b579f3SBram Moolenaar curwin->w_cursor.coladd = 0;
5018a9b579f3SBram Moolenaar }
5019a9b579f3SBram Moolenaar arg = startarg;
5020c6538bccSBram Moolenaar
5021a80faa89SBram Moolenaar CLEAR_FIELD(funcexe);
5022c6538bccSBram Moolenaar funcexe.firstline = eap->line1;
5023c6538bccSBram Moolenaar funcexe.lastline = eap->line2;
5024c6538bccSBram Moolenaar funcexe.doesrange = &doesrange;
5025c6538bccSBram Moolenaar funcexe.evaluate = !eap->skip;
5026c6538bccSBram Moolenaar funcexe.partial = partial;
5027c6538bccSBram Moolenaar funcexe.selfdict = fudi.fd_dict;
502832b3f820SBram Moolenaar funcexe.check_type = type;
502901dd6c37SBram Moolenaar rettv.v_type = VAR_UNKNOWN; // clear_tv() uses this
5030e6b5324eSBram Moolenaar if (get_func_tv(name, -1, &rettv, &arg, &evalarg, &funcexe) == FAIL)
5031a9b579f3SBram Moolenaar {
5032a9b579f3SBram Moolenaar failed = TRUE;
5033a9b579f3SBram Moolenaar break;
5034a9b579f3SBram Moolenaar }
5035c6f9f739SBram Moolenaar if (has_watchexpr())
5036c6f9f739SBram Moolenaar dbg_check_breakpoint(eap);
5037a9b579f3SBram Moolenaar
50389cfe8f6eSBram Moolenaar // Handle a function returning a Funcref, Dictionary or List.
5039e40fbc2cSBram Moolenaar if (handle_subscript(&arg, &rettv,
5040e40fbc2cSBram Moolenaar eap->skip ? NULL : &EVALARG_EVALUATE, TRUE) == FAIL)
5041a9b579f3SBram Moolenaar {
5042a9b579f3SBram Moolenaar failed = TRUE;
5043a9b579f3SBram Moolenaar break;
5044a9b579f3SBram Moolenaar }
5045a9b579f3SBram Moolenaar
5046a9b579f3SBram Moolenaar clear_tv(&rettv);
5047a9b579f3SBram Moolenaar if (doesrange || eap->skip)
5048a9b579f3SBram Moolenaar break;
5049a9b579f3SBram Moolenaar
5050e38eab22SBram Moolenaar // Stop when immediately aborting on error, or when an interrupt
5051e38eab22SBram Moolenaar // occurred or an exception was thrown but not caught.
5052e38eab22SBram Moolenaar // get_func_tv() returned OK, so that the check for trailing
5053e38eab22SBram Moolenaar // characters below is executed.
5054a9b579f3SBram Moolenaar if (aborting())
5055a9b579f3SBram Moolenaar break;
5056a9b579f3SBram Moolenaar }
5057a9b579f3SBram Moolenaar if (eap->skip)
5058a9b579f3SBram Moolenaar --emsg_skip;
5059e6b5324eSBram Moolenaar clear_evalarg(&evalarg, eap);
5060a9b579f3SBram Moolenaar
50611d34189eSBram Moolenaar // When inside :try we need to check for following "| catch" or "| endtry".
50621d34189eSBram Moolenaar // Not when there was an error, but do check if an exception was thrown.
50631d34189eSBram Moolenaar if ((!aborting() || did_throw)
50641d34189eSBram Moolenaar && (!failed || eap->cstack->cs_trylevel > 0))
5065a9b579f3SBram Moolenaar {
5066e38eab22SBram Moolenaar // Check for trailing illegal characters and a following command.
50678294d499SBram Moolenaar arg = skipwhite(arg);
5068a72cfb80SBram Moolenaar if (!ends_excmd2(eap->arg, arg))
5069a9b579f3SBram Moolenaar {
50701d34189eSBram Moolenaar if (!failed && !aborting())
507140d9da2aSBram Moolenaar {
5072a9b579f3SBram Moolenaar emsg_severe = TRUE;
50732d06bfdeSBram Moolenaar semsg(_(e_trailing_arg), arg);
5074a9b579f3SBram Moolenaar }
507540d9da2aSBram Moolenaar }
5076a9b579f3SBram Moolenaar else
507763b91736SBram Moolenaar set_nextcmd(eap, arg);
5078a9b579f3SBram Moolenaar }
5079a9b579f3SBram Moolenaar
5080a9b579f3SBram Moolenaar end:
5081a9b579f3SBram Moolenaar dict_unref(fudi.fd_dict);
5082a9b579f3SBram Moolenaar vim_free(tofree);
5083a9b579f3SBram Moolenaar }
5084a9b579f3SBram Moolenaar
5085a9b579f3SBram Moolenaar /*
5086a9b579f3SBram Moolenaar * Return from a function. Possibly makes the return pending. Also called
5087a9b579f3SBram Moolenaar * for a pending return at the ":endtry" or after returning from an extra
5088a9b579f3SBram Moolenaar * do_cmdline(). "reanimate" is used in the latter case. "is_cmd" is set
5089a9b579f3SBram Moolenaar * when called due to a ":return" command. "rettv" may point to a typval_T
5090a9b579f3SBram Moolenaar * with the return rettv. Returns TRUE when the return can be carried out,
5091a9b579f3SBram Moolenaar * FALSE when the return gets pending.
5092a9b579f3SBram Moolenaar */
5093a9b579f3SBram Moolenaar int
do_return(exarg_T * eap,int reanimate,int is_cmd,void * rettv)5094a9b579f3SBram Moolenaar do_return(
5095a9b579f3SBram Moolenaar exarg_T *eap,
5096a9b579f3SBram Moolenaar int reanimate,
5097a9b579f3SBram Moolenaar int is_cmd,
5098a9b579f3SBram Moolenaar void *rettv)
5099a9b579f3SBram Moolenaar {
5100a9b579f3SBram Moolenaar int idx;
5101ddef1291SBram Moolenaar cstack_T *cstack = eap->cstack;
5102a9b579f3SBram Moolenaar
5103a9b579f3SBram Moolenaar if (reanimate)
5104e38eab22SBram Moolenaar // Undo the return.
5105a9b579f3SBram Moolenaar current_funccal->returned = FALSE;
5106a9b579f3SBram Moolenaar
5107a9b579f3SBram Moolenaar /*
5108a9b579f3SBram Moolenaar * Cleanup (and inactivate) conditionals, but stop when a try conditional
5109a9b579f3SBram Moolenaar * not in its finally clause (which then is to be executed next) is found.
5110a9b579f3SBram Moolenaar * In this case, make the ":return" pending for execution at the ":endtry".
5111a9b579f3SBram Moolenaar * Otherwise, return normally.
5112a9b579f3SBram Moolenaar */
5113a9b579f3SBram Moolenaar idx = cleanup_conditionals(eap->cstack, 0, TRUE);
5114a9b579f3SBram Moolenaar if (idx >= 0)
5115a9b579f3SBram Moolenaar {
5116a9b579f3SBram Moolenaar cstack->cs_pending[idx] = CSTP_RETURN;
5117a9b579f3SBram Moolenaar
5118a9b579f3SBram Moolenaar if (!is_cmd && !reanimate)
5119e38eab22SBram Moolenaar // A pending return again gets pending. "rettv" points to an
5120e38eab22SBram Moolenaar // allocated variable with the rettv of the original ":return"'s
5121e38eab22SBram Moolenaar // argument if present or is NULL else.
5122a9b579f3SBram Moolenaar cstack->cs_rettv[idx] = rettv;
5123a9b579f3SBram Moolenaar else
5124a9b579f3SBram Moolenaar {
5125e38eab22SBram Moolenaar // When undoing a return in order to make it pending, get the stored
5126e38eab22SBram Moolenaar // return rettv.
5127a9b579f3SBram Moolenaar if (reanimate)
5128a9b579f3SBram Moolenaar rettv = current_funccal->rettv;
5129a9b579f3SBram Moolenaar
5130a9b579f3SBram Moolenaar if (rettv != NULL)
5131a9b579f3SBram Moolenaar {
5132e38eab22SBram Moolenaar // Store the value of the pending return.
5133a9b579f3SBram Moolenaar if ((cstack->cs_rettv[idx] = alloc_tv()) != NULL)
5134a9b579f3SBram Moolenaar *(typval_T *)cstack->cs_rettv[idx] = *(typval_T *)rettv;
5135a9b579f3SBram Moolenaar else
5136e29a27f6SBram Moolenaar emsg(_(e_out_of_memory));
5137a9b579f3SBram Moolenaar }
5138a9b579f3SBram Moolenaar else
5139a9b579f3SBram Moolenaar cstack->cs_rettv[idx] = NULL;
5140a9b579f3SBram Moolenaar
5141a9b579f3SBram Moolenaar if (reanimate)
5142a9b579f3SBram Moolenaar {
5143e38eab22SBram Moolenaar // The pending return value could be overwritten by a ":return"
5144e38eab22SBram Moolenaar // without argument in a finally clause; reset the default
5145e38eab22SBram Moolenaar // return value.
5146a9b579f3SBram Moolenaar current_funccal->rettv->v_type = VAR_NUMBER;
5147a9b579f3SBram Moolenaar current_funccal->rettv->vval.v_number = 0;
5148a9b579f3SBram Moolenaar }
5149a9b579f3SBram Moolenaar }
5150a9b579f3SBram Moolenaar report_make_pending(CSTP_RETURN, rettv);
5151a9b579f3SBram Moolenaar }
5152a9b579f3SBram Moolenaar else
5153a9b579f3SBram Moolenaar {
5154a9b579f3SBram Moolenaar current_funccal->returned = TRUE;
5155a9b579f3SBram Moolenaar
5156e38eab22SBram Moolenaar // If the return is carried out now, store the return value. For
5157e38eab22SBram Moolenaar // a return immediately after reanimation, the value is already
5158e38eab22SBram Moolenaar // there.
5159a9b579f3SBram Moolenaar if (!reanimate && rettv != NULL)
5160a9b579f3SBram Moolenaar {
5161a9b579f3SBram Moolenaar clear_tv(current_funccal->rettv);
5162a9b579f3SBram Moolenaar *current_funccal->rettv = *(typval_T *)rettv;
5163a9b579f3SBram Moolenaar if (!is_cmd)
5164a9b579f3SBram Moolenaar vim_free(rettv);
5165a9b579f3SBram Moolenaar }
5166a9b579f3SBram Moolenaar }
5167a9b579f3SBram Moolenaar
5168a9b579f3SBram Moolenaar return idx < 0;
5169a9b579f3SBram Moolenaar }
5170a9b579f3SBram Moolenaar
5171a9b579f3SBram Moolenaar /*
5172a9b579f3SBram Moolenaar * Free the variable with a pending return value.
5173a9b579f3SBram Moolenaar */
5174a9b579f3SBram Moolenaar void
discard_pending_return(void * rettv)5175a9b579f3SBram Moolenaar discard_pending_return(void *rettv)
5176a9b579f3SBram Moolenaar {
5177a9b579f3SBram Moolenaar free_tv((typval_T *)rettv);
5178a9b579f3SBram Moolenaar }
5179a9b579f3SBram Moolenaar
5180a9b579f3SBram Moolenaar /*
5181a9b579f3SBram Moolenaar * Generate a return command for producing the value of "rettv". The result
5182a9b579f3SBram Moolenaar * is an allocated string. Used by report_pending() for verbose messages.
5183a9b579f3SBram Moolenaar */
5184a9b579f3SBram Moolenaar char_u *
get_return_cmd(void * rettv)5185a9b579f3SBram Moolenaar get_return_cmd(void *rettv)
5186a9b579f3SBram Moolenaar {
5187a9b579f3SBram Moolenaar char_u *s = NULL;
5188a9b579f3SBram Moolenaar char_u *tofree = NULL;
5189a9b579f3SBram Moolenaar char_u numbuf[NUMBUFLEN];
5190a9b579f3SBram Moolenaar
5191a9b579f3SBram Moolenaar if (rettv != NULL)
5192a9b579f3SBram Moolenaar s = echo_string((typval_T *)rettv, &tofree, numbuf, 0);
5193a9b579f3SBram Moolenaar if (s == NULL)
5194a9b579f3SBram Moolenaar s = (char_u *)"";
5195a9b579f3SBram Moolenaar
5196a9b579f3SBram Moolenaar STRCPY(IObuff, ":return ");
5197a9b579f3SBram Moolenaar STRNCPY(IObuff + 8, s, IOSIZE - 8);
5198a9b579f3SBram Moolenaar if (STRLEN(s) + 8 >= IOSIZE)
5199a9b579f3SBram Moolenaar STRCPY(IObuff + IOSIZE - 4, "...");
5200a9b579f3SBram Moolenaar vim_free(tofree);
5201a9b579f3SBram Moolenaar return vim_strsave(IObuff);
5202a9b579f3SBram Moolenaar }
5203a9b579f3SBram Moolenaar
5204a9b579f3SBram Moolenaar /*
5205a9b579f3SBram Moolenaar * Get next function line.
5206a9b579f3SBram Moolenaar * Called by do_cmdline() to get the next line.
5207a9b579f3SBram Moolenaar * Returns allocated string, or NULL for end of function.
5208a9b579f3SBram Moolenaar */
5209a9b579f3SBram Moolenaar char_u *
get_func_line(int c UNUSED,void * cookie,int indent UNUSED,getline_opt_T options UNUSED)5210a9b579f3SBram Moolenaar get_func_line(
5211a9b579f3SBram Moolenaar int c UNUSED,
5212a9b579f3SBram Moolenaar void *cookie,
5213e96a2498SBram Moolenaar int indent UNUSED,
521466250c93SBram Moolenaar getline_opt_T options UNUSED)
5215a9b579f3SBram Moolenaar {
5216a9b579f3SBram Moolenaar funccall_T *fcp = (funccall_T *)cookie;
5217a9b579f3SBram Moolenaar ufunc_T *fp = fcp->func;
5218a9b579f3SBram Moolenaar char_u *retval;
5219e38eab22SBram Moolenaar garray_T *gap; // growarray with function lines
5220a9b579f3SBram Moolenaar
5221e38eab22SBram Moolenaar // If breakpoints have been added/deleted need to check for it.
5222a9b579f3SBram Moolenaar if (fcp->dbg_tick != debug_tick)
5223a9b579f3SBram Moolenaar {
5224a9b579f3SBram Moolenaar fcp->breakpoint = dbg_find_breakpoint(FALSE, fp->uf_name,
52251a47ae32SBram Moolenaar SOURCING_LNUM);
5226a9b579f3SBram Moolenaar fcp->dbg_tick = debug_tick;
5227a9b579f3SBram Moolenaar }
5228a9b579f3SBram Moolenaar #ifdef FEAT_PROFILE
5229a9b579f3SBram Moolenaar if (do_profiling == PROF_YES)
5230a9b579f3SBram Moolenaar func_line_end(cookie);
5231a9b579f3SBram Moolenaar #endif
5232a9b579f3SBram Moolenaar
5233a9b579f3SBram Moolenaar gap = &fp->uf_lines;
5234a9b579f3SBram Moolenaar if (((fp->uf_flags & FC_ABORT) && did_emsg && !aborted_in_try())
5235a9b579f3SBram Moolenaar || fcp->returned)
5236a9b579f3SBram Moolenaar retval = NULL;
5237a9b579f3SBram Moolenaar else
5238a9b579f3SBram Moolenaar {
5239e38eab22SBram Moolenaar // Skip NULL lines (continuation lines).
5240a9b579f3SBram Moolenaar while (fcp->linenr < gap->ga_len
5241a9b579f3SBram Moolenaar && ((char_u **)(gap->ga_data))[fcp->linenr] == NULL)
5242a9b579f3SBram Moolenaar ++fcp->linenr;
5243a9b579f3SBram Moolenaar if (fcp->linenr >= gap->ga_len)
5244a9b579f3SBram Moolenaar retval = NULL;
5245a9b579f3SBram Moolenaar else
5246a9b579f3SBram Moolenaar {
5247a9b579f3SBram Moolenaar retval = vim_strsave(((char_u **)(gap->ga_data))[fcp->linenr++]);
52481a47ae32SBram Moolenaar SOURCING_LNUM = fcp->linenr;
5249a9b579f3SBram Moolenaar #ifdef FEAT_PROFILE
5250a9b579f3SBram Moolenaar if (do_profiling == PROF_YES)
5251b2049903SBram Moolenaar func_line_start(cookie, SOURCING_LNUM);
5252a9b579f3SBram Moolenaar #endif
5253a9b579f3SBram Moolenaar }
5254a9b579f3SBram Moolenaar }
5255a9b579f3SBram Moolenaar
5256e38eab22SBram Moolenaar // Did we encounter a breakpoint?
52571a47ae32SBram Moolenaar if (fcp->breakpoint != 0 && fcp->breakpoint <= SOURCING_LNUM)
5258a9b579f3SBram Moolenaar {
52591a47ae32SBram Moolenaar dbg_breakpoint(fp->uf_name, SOURCING_LNUM);
5260e38eab22SBram Moolenaar // Find next breakpoint.
5261a9b579f3SBram Moolenaar fcp->breakpoint = dbg_find_breakpoint(FALSE, fp->uf_name,
52621a47ae32SBram Moolenaar SOURCING_LNUM);
5263a9b579f3SBram Moolenaar fcp->dbg_tick = debug_tick;
5264a9b579f3SBram Moolenaar }
5265a9b579f3SBram Moolenaar
5266a9b579f3SBram Moolenaar return retval;
5267a9b579f3SBram Moolenaar }
5268a9b579f3SBram Moolenaar
5269a9b579f3SBram Moolenaar /*
5270a9b579f3SBram Moolenaar * Return TRUE if the currently active function should be ended, because a
5271a9b579f3SBram Moolenaar * return was encountered or an error occurred. Used inside a ":while".
5272a9b579f3SBram Moolenaar */
5273a9b579f3SBram Moolenaar int
func_has_ended(void * cookie)5274a9b579f3SBram Moolenaar func_has_ended(void *cookie)
5275a9b579f3SBram Moolenaar {
5276a9b579f3SBram Moolenaar funccall_T *fcp = (funccall_T *)cookie;
5277a9b579f3SBram Moolenaar
5278e38eab22SBram Moolenaar // Ignore the "abort" flag if the abortion behavior has been changed due to
5279e38eab22SBram Moolenaar // an error inside a try conditional.
5280a9b579f3SBram Moolenaar return (((fcp->func->uf_flags & FC_ABORT) && did_emsg && !aborted_in_try())
5281a9b579f3SBram Moolenaar || fcp->returned);
5282a9b579f3SBram Moolenaar }
5283a9b579f3SBram Moolenaar
5284a9b579f3SBram Moolenaar /*
5285a9b579f3SBram Moolenaar * return TRUE if cookie indicates a function which "abort"s on errors.
5286a9b579f3SBram Moolenaar */
5287a9b579f3SBram Moolenaar int
func_has_abort(void * cookie)5288a9b579f3SBram Moolenaar func_has_abort(
5289a9b579f3SBram Moolenaar void *cookie)
5290a9b579f3SBram Moolenaar {
5291a9b579f3SBram Moolenaar return ((funccall_T *)cookie)->func->uf_flags & FC_ABORT;
5292a9b579f3SBram Moolenaar }
5293a9b579f3SBram Moolenaar
5294a9b579f3SBram Moolenaar
5295a9b579f3SBram Moolenaar /*
5296a9b579f3SBram Moolenaar * Turn "dict.Func" into a partial for "Func" bound to "dict".
5297a9b579f3SBram Moolenaar * Don't do this when "Func" is already a partial that was bound
5298a9b579f3SBram Moolenaar * explicitly (pt_auto is FALSE).
5299a9b579f3SBram Moolenaar * Changes "rettv" in-place.
5300a9b579f3SBram Moolenaar * Returns the updated "selfdict_in".
5301a9b579f3SBram Moolenaar */
5302a9b579f3SBram Moolenaar dict_T *
make_partial(dict_T * selfdict_in,typval_T * rettv)5303a9b579f3SBram Moolenaar make_partial(dict_T *selfdict_in, typval_T *rettv)
5304a9b579f3SBram Moolenaar {
5305437bafe4SBram Moolenaar char_u *fname;
5306a9b579f3SBram Moolenaar char_u *tofree = NULL;
5307a9b579f3SBram Moolenaar ufunc_T *fp;
5308a9b579f3SBram Moolenaar char_u fname_buf[FLEN_FIXED + 1];
5309a9b579f3SBram Moolenaar int error;
5310a9b579f3SBram Moolenaar dict_T *selfdict = selfdict_in;
5311a9b579f3SBram Moolenaar
5312437bafe4SBram Moolenaar if (rettv->v_type == VAR_PARTIAL && rettv->vval.v_partial->pt_func != NULL)
5313437bafe4SBram Moolenaar fp = rettv->vval.v_partial->pt_func;
5314437bafe4SBram Moolenaar else
5315437bafe4SBram Moolenaar {
5316437bafe4SBram Moolenaar fname = rettv->v_type == VAR_FUNC ? rettv->vval.v_string
5317437bafe4SBram Moolenaar : rettv->vval.v_partial->pt_name;
5318e38eab22SBram Moolenaar // Translate "s:func" to the stored function name.
5319a9b579f3SBram Moolenaar fname = fname_trans_sid(fname, fname_buf, &tofree, &error);
53204c17ad94SBram Moolenaar fp = find_func(fname, FALSE, NULL);
5321a9b579f3SBram Moolenaar vim_free(tofree);
5322437bafe4SBram Moolenaar }
5323a9b579f3SBram Moolenaar
5324a9b579f3SBram Moolenaar if (fp != NULL && (fp->uf_flags & FC_DICT))
5325a9b579f3SBram Moolenaar {
5326c799fe20SBram Moolenaar partial_T *pt = ALLOC_CLEAR_ONE(partial_T);
5327a9b579f3SBram Moolenaar
5328a9b579f3SBram Moolenaar if (pt != NULL)
5329a9b579f3SBram Moolenaar {
5330a9b579f3SBram Moolenaar pt->pt_refcount = 1;
5331a9b579f3SBram Moolenaar pt->pt_dict = selfdict;
5332a9b579f3SBram Moolenaar pt->pt_auto = TRUE;
5333a9b579f3SBram Moolenaar selfdict = NULL;
5334a9b579f3SBram Moolenaar if (rettv->v_type == VAR_FUNC)
5335a9b579f3SBram Moolenaar {
5336e38eab22SBram Moolenaar // Just a function: Take over the function name and use
5337e38eab22SBram Moolenaar // selfdict.
5338a9b579f3SBram Moolenaar pt->pt_name = rettv->vval.v_string;
5339a9b579f3SBram Moolenaar }
5340a9b579f3SBram Moolenaar else
5341a9b579f3SBram Moolenaar {
5342a9b579f3SBram Moolenaar partial_T *ret_pt = rettv->vval.v_partial;
5343a9b579f3SBram Moolenaar int i;
5344a9b579f3SBram Moolenaar
5345e38eab22SBram Moolenaar // Partial: copy the function name, use selfdict and copy
5346e38eab22SBram Moolenaar // args. Can't take over name or args, the partial might
5347e38eab22SBram Moolenaar // be referenced elsewhere.
5348437bafe4SBram Moolenaar if (ret_pt->pt_name != NULL)
5349437bafe4SBram Moolenaar {
5350a9b579f3SBram Moolenaar pt->pt_name = vim_strsave(ret_pt->pt_name);
5351a9b579f3SBram Moolenaar func_ref(pt->pt_name);
5352437bafe4SBram Moolenaar }
5353437bafe4SBram Moolenaar else
5354437bafe4SBram Moolenaar {
5355437bafe4SBram Moolenaar pt->pt_func = ret_pt->pt_func;
5356437bafe4SBram Moolenaar func_ptr_ref(pt->pt_func);
5357437bafe4SBram Moolenaar }
5358a9b579f3SBram Moolenaar if (ret_pt->pt_argc > 0)
5359a9b579f3SBram Moolenaar {
5360c799fe20SBram Moolenaar pt->pt_argv = ALLOC_MULT(typval_T, ret_pt->pt_argc);
5361a9b579f3SBram Moolenaar if (pt->pt_argv == NULL)
5362e38eab22SBram Moolenaar // out of memory: drop the arguments
5363a9b579f3SBram Moolenaar pt->pt_argc = 0;
5364a9b579f3SBram Moolenaar else
5365a9b579f3SBram Moolenaar {
5366a9b579f3SBram Moolenaar pt->pt_argc = ret_pt->pt_argc;
5367a9b579f3SBram Moolenaar for (i = 0; i < pt->pt_argc; i++)
5368a9b579f3SBram Moolenaar copy_tv(&ret_pt->pt_argv[i], &pt->pt_argv[i]);
5369a9b579f3SBram Moolenaar }
5370a9b579f3SBram Moolenaar }
5371a9b579f3SBram Moolenaar partial_unref(ret_pt);
5372a9b579f3SBram Moolenaar }
5373a9b579f3SBram Moolenaar rettv->v_type = VAR_PARTIAL;
5374a9b579f3SBram Moolenaar rettv->vval.v_partial = pt;
5375a9b579f3SBram Moolenaar }
5376a9b579f3SBram Moolenaar }
5377a9b579f3SBram Moolenaar return selfdict;
5378a9b579f3SBram Moolenaar }
5379a9b579f3SBram Moolenaar
5380a9b579f3SBram Moolenaar /*
5381a9b579f3SBram Moolenaar * Return the name of the executed function.
5382a9b579f3SBram Moolenaar */
5383a9b579f3SBram Moolenaar char_u *
func_name(void * cookie)5384a9b579f3SBram Moolenaar func_name(void *cookie)
5385a9b579f3SBram Moolenaar {
5386a9b579f3SBram Moolenaar return ((funccall_T *)cookie)->func->uf_name;
5387a9b579f3SBram Moolenaar }
5388a9b579f3SBram Moolenaar
5389a9b579f3SBram Moolenaar /*
5390a9b579f3SBram Moolenaar * Return the address holding the next breakpoint line for a funccall cookie.
5391a9b579f3SBram Moolenaar */
5392a9b579f3SBram Moolenaar linenr_T *
func_breakpoint(void * cookie)5393a9b579f3SBram Moolenaar func_breakpoint(void *cookie)
5394a9b579f3SBram Moolenaar {
5395a9b579f3SBram Moolenaar return &((funccall_T *)cookie)->breakpoint;
5396a9b579f3SBram Moolenaar }
5397a9b579f3SBram Moolenaar
5398a9b579f3SBram Moolenaar /*
5399a9b579f3SBram Moolenaar * Return the address holding the debug tick for a funccall cookie.
5400a9b579f3SBram Moolenaar */
5401a9b579f3SBram Moolenaar int *
func_dbg_tick(void * cookie)5402a9b579f3SBram Moolenaar func_dbg_tick(void *cookie)
5403a9b579f3SBram Moolenaar {
5404a9b579f3SBram Moolenaar return &((funccall_T *)cookie)->dbg_tick;
5405a9b579f3SBram Moolenaar }
5406a9b579f3SBram Moolenaar
5407a9b579f3SBram Moolenaar /*
5408a9b579f3SBram Moolenaar * Return the nesting level for a funccall cookie.
5409a9b579f3SBram Moolenaar */
5410a9b579f3SBram Moolenaar int
func_level(void * cookie)5411a9b579f3SBram Moolenaar func_level(void *cookie)
5412a9b579f3SBram Moolenaar {
5413a9b579f3SBram Moolenaar return ((funccall_T *)cookie)->level;
5414a9b579f3SBram Moolenaar }
5415a9b579f3SBram Moolenaar
5416a9b579f3SBram Moolenaar /*
5417a9b579f3SBram Moolenaar * Return TRUE when a function was ended by a ":return" command.
5418a9b579f3SBram Moolenaar */
5419a9b579f3SBram Moolenaar int
current_func_returned(void)5420a9b579f3SBram Moolenaar current_func_returned(void)
5421a9b579f3SBram Moolenaar {
5422a9b579f3SBram Moolenaar return current_funccal->returned;
5423a9b579f3SBram Moolenaar }
5424a9b579f3SBram Moolenaar
5425a9b579f3SBram Moolenaar int
free_unref_funccal(int copyID,int testing)5426a9b579f3SBram Moolenaar free_unref_funccal(int copyID, int testing)
5427a9b579f3SBram Moolenaar {
5428a9b579f3SBram Moolenaar int did_free = FALSE;
5429a9b579f3SBram Moolenaar int did_free_funccal = FALSE;
5430a9b579f3SBram Moolenaar funccall_T *fc, **pfc;
5431a9b579f3SBram Moolenaar
5432a9b579f3SBram Moolenaar for (pfc = &previous_funccal; *pfc != NULL; )
5433a9b579f3SBram Moolenaar {
5434a9b579f3SBram Moolenaar if (can_free_funccal(*pfc, copyID))
5435a9b579f3SBram Moolenaar {
5436a9b579f3SBram Moolenaar fc = *pfc;
5437a9b579f3SBram Moolenaar *pfc = fc->caller;
5438209b8e3eSBram Moolenaar free_funccal_contents(fc);
5439a9b579f3SBram Moolenaar did_free = TRUE;
5440a9b579f3SBram Moolenaar did_free_funccal = TRUE;
5441a9b579f3SBram Moolenaar }
5442a9b579f3SBram Moolenaar else
5443a9b579f3SBram Moolenaar pfc = &(*pfc)->caller;
5444a9b579f3SBram Moolenaar }
5445a9b579f3SBram Moolenaar if (did_free_funccal)
5446e38eab22SBram Moolenaar // When a funccal was freed some more items might be garbage
5447e38eab22SBram Moolenaar // collected, so run again.
5448a9b579f3SBram Moolenaar (void)garbage_collect(testing);
5449a9b579f3SBram Moolenaar
5450a9b579f3SBram Moolenaar return did_free;
5451a9b579f3SBram Moolenaar }
5452a9b579f3SBram Moolenaar
5453a9b579f3SBram Moolenaar /*
5454ba209903SBram Moolenaar * Get function call environment based on backtrace debug level
5455a9b579f3SBram Moolenaar */
5456a9b579f3SBram Moolenaar static funccall_T *
get_funccal(void)5457a9b579f3SBram Moolenaar get_funccal(void)
5458a9b579f3SBram Moolenaar {
5459a9b579f3SBram Moolenaar int i;
5460a9b579f3SBram Moolenaar funccall_T *funccal;
5461a9b579f3SBram Moolenaar funccall_T *temp_funccal;
5462a9b579f3SBram Moolenaar
5463a9b579f3SBram Moolenaar funccal = current_funccal;
5464a9b579f3SBram Moolenaar if (debug_backtrace_level > 0)
5465a9b579f3SBram Moolenaar {
5466a9b579f3SBram Moolenaar for (i = 0; i < debug_backtrace_level; i++)
5467a9b579f3SBram Moolenaar {
5468a9b579f3SBram Moolenaar temp_funccal = funccal->caller;
5469a9b579f3SBram Moolenaar if (temp_funccal)
5470a9b579f3SBram Moolenaar funccal = temp_funccal;
5471a9b579f3SBram Moolenaar else
5472e38eab22SBram Moolenaar // backtrace level overflow. reset to max
5473a9b579f3SBram Moolenaar debug_backtrace_level = i;
5474a9b579f3SBram Moolenaar }
5475a9b579f3SBram Moolenaar }
5476a9b579f3SBram Moolenaar return funccal;
5477a9b579f3SBram Moolenaar }
5478a9b579f3SBram Moolenaar
5479a9b579f3SBram Moolenaar /*
5480a9b579f3SBram Moolenaar * Return the hashtable used for local variables in the current funccal.
5481a9b579f3SBram Moolenaar * Return NULL if there is no current funccal.
5482a9b579f3SBram Moolenaar */
5483a9b579f3SBram Moolenaar hashtab_T *
get_funccal_local_ht()5484a9b579f3SBram Moolenaar get_funccal_local_ht()
5485a9b579f3SBram Moolenaar {
54868a7d6542SBram Moolenaar if (current_funccal == NULL || current_funccal->l_vars.dv_refcount == 0)
5487a9b579f3SBram Moolenaar return NULL;
5488a9b579f3SBram Moolenaar return &get_funccal()->l_vars.dv_hashtab;
5489a9b579f3SBram Moolenaar }
5490a9b579f3SBram Moolenaar
5491a9b579f3SBram Moolenaar /*
5492a9b579f3SBram Moolenaar * Return the l: scope variable.
5493a9b579f3SBram Moolenaar * Return NULL if there is no current funccal.
5494a9b579f3SBram Moolenaar */
5495a9b579f3SBram Moolenaar dictitem_T *
get_funccal_local_var()5496a9b579f3SBram Moolenaar get_funccal_local_var()
5497a9b579f3SBram Moolenaar {
54988a7d6542SBram Moolenaar if (current_funccal == NULL || current_funccal->l_vars.dv_refcount == 0)
5499a9b579f3SBram Moolenaar return NULL;
5500a9b579f3SBram Moolenaar return &get_funccal()->l_vars_var;
5501a9b579f3SBram Moolenaar }
5502a9b579f3SBram Moolenaar
5503a9b579f3SBram Moolenaar /*
5504a9b579f3SBram Moolenaar * Return the hashtable used for argument in the current funccal.
5505a9b579f3SBram Moolenaar * Return NULL if there is no current funccal.
5506a9b579f3SBram Moolenaar */
5507a9b579f3SBram Moolenaar hashtab_T *
get_funccal_args_ht()5508a9b579f3SBram Moolenaar get_funccal_args_ht()
5509a9b579f3SBram Moolenaar {
55108a7d6542SBram Moolenaar if (current_funccal == NULL || current_funccal->l_vars.dv_refcount == 0)
5511a9b579f3SBram Moolenaar return NULL;
5512a9b579f3SBram Moolenaar return &get_funccal()->l_avars.dv_hashtab;
5513a9b579f3SBram Moolenaar }
5514a9b579f3SBram Moolenaar
5515a9b579f3SBram Moolenaar /*
5516a9b579f3SBram Moolenaar * Return the a: scope variable.
5517a9b579f3SBram Moolenaar * Return NULL if there is no current funccal.
5518a9b579f3SBram Moolenaar */
5519a9b579f3SBram Moolenaar dictitem_T *
get_funccal_args_var()5520a9b579f3SBram Moolenaar get_funccal_args_var()
5521a9b579f3SBram Moolenaar {
55228a7d6542SBram Moolenaar if (current_funccal == NULL || current_funccal->l_vars.dv_refcount == 0)
5523a9b579f3SBram Moolenaar return NULL;
5524c7d9eaceSBram Moolenaar return &get_funccal()->l_avars_var;
5525a9b579f3SBram Moolenaar }
5526a9b579f3SBram Moolenaar
5527a9b579f3SBram Moolenaar /*
5528a9b579f3SBram Moolenaar * List function variables, if there is a function.
5529a9b579f3SBram Moolenaar */
5530a9b579f3SBram Moolenaar void
list_func_vars(int * first)5531a9b579f3SBram Moolenaar list_func_vars(int *first)
5532a9b579f3SBram Moolenaar {
55338a7d6542SBram Moolenaar if (current_funccal != NULL && current_funccal->l_vars.dv_refcount > 0)
5534a9b579f3SBram Moolenaar list_hashtable_vars(¤t_funccal->l_vars.dv_hashtab,
553532526b3cSBram Moolenaar "l:", FALSE, first);
5536a9b579f3SBram Moolenaar }
5537a9b579f3SBram Moolenaar
5538a9b579f3SBram Moolenaar /*
5539a9b579f3SBram Moolenaar * If "ht" is the hashtable for local variables in the current funccal, return
5540a9b579f3SBram Moolenaar * the dict that contains it.
5541a9b579f3SBram Moolenaar * Otherwise return NULL.
5542a9b579f3SBram Moolenaar */
5543a9b579f3SBram Moolenaar dict_T *
get_current_funccal_dict(hashtab_T * ht)5544a9b579f3SBram Moolenaar get_current_funccal_dict(hashtab_T *ht)
5545a9b579f3SBram Moolenaar {
5546a9b579f3SBram Moolenaar if (current_funccal != NULL
5547a9b579f3SBram Moolenaar && ht == ¤t_funccal->l_vars.dv_hashtab)
5548a9b579f3SBram Moolenaar return ¤t_funccal->l_vars;
5549a9b579f3SBram Moolenaar return NULL;
5550a9b579f3SBram Moolenaar }
5551a9b579f3SBram Moolenaar
5552a9b579f3SBram Moolenaar /*
555310ce39a0SBram Moolenaar * Search hashitem in parent scope.
555410ce39a0SBram Moolenaar */
555510ce39a0SBram Moolenaar hashitem_T *
find_hi_in_scoped_ht(char_u * name,hashtab_T ** pht)5556ba96e9afSBram Moolenaar find_hi_in_scoped_ht(char_u *name, hashtab_T **pht)
555710ce39a0SBram Moolenaar {
555810ce39a0SBram Moolenaar funccall_T *old_current_funccal = current_funccal;
555910ce39a0SBram Moolenaar hashtab_T *ht;
556010ce39a0SBram Moolenaar hashitem_T *hi = NULL;
5561ba96e9afSBram Moolenaar char_u *varname;
556210ce39a0SBram Moolenaar
556310ce39a0SBram Moolenaar if (current_funccal == NULL || current_funccal->func->uf_scoped == NULL)
556410ce39a0SBram Moolenaar return NULL;
556510ce39a0SBram Moolenaar
55666f5b6dfbSBram Moolenaar // Search in parent scope, which can be referenced from a lambda.
556710ce39a0SBram Moolenaar current_funccal = current_funccal->func->uf_scoped;
556858016448SBram Moolenaar while (current_funccal != NULL)
556910ce39a0SBram Moolenaar {
5570ba96e9afSBram Moolenaar ht = find_var_ht(name, &varname);
5571ba96e9afSBram Moolenaar if (ht != NULL && *varname != NUL)
557210ce39a0SBram Moolenaar {
5573ba96e9afSBram Moolenaar hi = hash_find(ht, varname);
557410ce39a0SBram Moolenaar if (!HASHITEM_EMPTY(hi))
557510ce39a0SBram Moolenaar {
557610ce39a0SBram Moolenaar *pht = ht;
557710ce39a0SBram Moolenaar break;
557810ce39a0SBram Moolenaar }
557910ce39a0SBram Moolenaar }
558010ce39a0SBram Moolenaar if (current_funccal == current_funccal->func->uf_scoped)
558110ce39a0SBram Moolenaar break;
558210ce39a0SBram Moolenaar current_funccal = current_funccal->func->uf_scoped;
558310ce39a0SBram Moolenaar }
558410ce39a0SBram Moolenaar current_funccal = old_current_funccal;
558510ce39a0SBram Moolenaar
558610ce39a0SBram Moolenaar return hi;
558710ce39a0SBram Moolenaar }
558810ce39a0SBram Moolenaar
558910ce39a0SBram Moolenaar /*
55901e96d9bfSBram Moolenaar * Search variable in parent scope.
55911e96d9bfSBram Moolenaar */
55921e96d9bfSBram Moolenaar dictitem_T *
find_var_in_scoped_ht(char_u * name,int no_autoload)5593ba96e9afSBram Moolenaar find_var_in_scoped_ht(char_u *name, int no_autoload)
55941e96d9bfSBram Moolenaar {
55951e96d9bfSBram Moolenaar dictitem_T *v = NULL;
55961e96d9bfSBram Moolenaar funccall_T *old_current_funccal = current_funccal;
55971e96d9bfSBram Moolenaar hashtab_T *ht;
5598ba96e9afSBram Moolenaar char_u *varname;
55991e96d9bfSBram Moolenaar
56001e96d9bfSBram Moolenaar if (current_funccal == NULL || current_funccal->func->uf_scoped == NULL)
56011e96d9bfSBram Moolenaar return NULL;
56021e96d9bfSBram Moolenaar
5603e38eab22SBram Moolenaar // Search in parent scope which is possible to reference from lambda
56041e96d9bfSBram Moolenaar current_funccal = current_funccal->func->uf_scoped;
56051e96d9bfSBram Moolenaar while (current_funccal)
56061e96d9bfSBram Moolenaar {
5607ba96e9afSBram Moolenaar ht = find_var_ht(name, &varname);
5608ba96e9afSBram Moolenaar if (ht != NULL && *varname != NUL)
56091e96d9bfSBram Moolenaar {
5610ba96e9afSBram Moolenaar v = find_var_in_ht(ht, *name, varname, no_autoload);
56111e96d9bfSBram Moolenaar if (v != NULL)
56121e96d9bfSBram Moolenaar break;
56131e96d9bfSBram Moolenaar }
56141e96d9bfSBram Moolenaar if (current_funccal == current_funccal->func->uf_scoped)
56151e96d9bfSBram Moolenaar break;
56161e96d9bfSBram Moolenaar current_funccal = current_funccal->func->uf_scoped;
56171e96d9bfSBram Moolenaar }
56181e96d9bfSBram Moolenaar current_funccal = old_current_funccal;
56191e96d9bfSBram Moolenaar
56201e96d9bfSBram Moolenaar return v;
56211e96d9bfSBram Moolenaar }
56221e96d9bfSBram Moolenaar
56231e96d9bfSBram Moolenaar /*
5624a9b579f3SBram Moolenaar * Set "copyID + 1" in previous_funccal and callers.
5625a9b579f3SBram Moolenaar */
5626a9b579f3SBram Moolenaar int
set_ref_in_previous_funccal(int copyID)5627a9b579f3SBram Moolenaar set_ref_in_previous_funccal(int copyID)
5628a9b579f3SBram Moolenaar {
5629a9b579f3SBram Moolenaar funccall_T *fc;
5630a9b579f3SBram Moolenaar
563120cc5283SBram Moolenaar for (fc = previous_funccal; fc != NULL; fc = fc->caller)
5632a9b579f3SBram Moolenaar {
56331e96d9bfSBram Moolenaar fc->fc_copyID = copyID + 1;
563420cc5283SBram Moolenaar if (set_ref_in_ht(&fc->l_vars.dv_hashtab, copyID + 1, NULL)
56356e5000d4SBram Moolenaar || set_ref_in_ht(&fc->l_avars.dv_hashtab, copyID + 1, NULL)
563620cc5283SBram Moolenaar || set_ref_in_list_items(&fc->l_varlist, copyID + 1, NULL))
563720cc5283SBram Moolenaar return TRUE;
5638a9b579f3SBram Moolenaar }
563920cc5283SBram Moolenaar return FALSE;
5640a9b579f3SBram Moolenaar }
5641a9b579f3SBram Moolenaar
5642bc7ce675SBram Moolenaar static int
set_ref_in_funccal(funccall_T * fc,int copyID)5643bc7ce675SBram Moolenaar set_ref_in_funccal(funccall_T *fc, int copyID)
5644bc7ce675SBram Moolenaar {
5645bc7ce675SBram Moolenaar if (fc->fc_copyID != copyID)
5646bc7ce675SBram Moolenaar {
5647bc7ce675SBram Moolenaar fc->fc_copyID = copyID;
564820cc5283SBram Moolenaar if (set_ref_in_ht(&fc->l_vars.dv_hashtab, copyID, NULL)
56496e5000d4SBram Moolenaar || set_ref_in_ht(&fc->l_avars.dv_hashtab, copyID, NULL)
56507be3ab25SBram Moolenaar || set_ref_in_list_items(&fc->l_varlist, copyID, NULL)
565120cc5283SBram Moolenaar || set_ref_in_func(NULL, fc->func, copyID))
565220cc5283SBram Moolenaar return TRUE;
5653bc7ce675SBram Moolenaar }
565420cc5283SBram Moolenaar return FALSE;
5655bc7ce675SBram Moolenaar }
5656bc7ce675SBram Moolenaar
5657a9b579f3SBram Moolenaar /*
5658a9b579f3SBram Moolenaar * Set "copyID" in all local vars and arguments in the call stack.
5659a9b579f3SBram Moolenaar */
5660a9b579f3SBram Moolenaar int
set_ref_in_call_stack(int copyID)5661a9b579f3SBram Moolenaar set_ref_in_call_stack(int copyID)
5662a9b579f3SBram Moolenaar {
5663a9b579f3SBram Moolenaar funccall_T *fc;
5664c07f67adSBram Moolenaar funccal_entry_T *entry;
5665a9b579f3SBram Moolenaar
566620cc5283SBram Moolenaar for (fc = current_funccal; fc != NULL; fc = fc->caller)
566720cc5283SBram Moolenaar if (set_ref_in_funccal(fc, copyID))
566820cc5283SBram Moolenaar return TRUE;
5669c07f67adSBram Moolenaar
5670c07f67adSBram Moolenaar // Also go through the funccal_stack.
567120cc5283SBram Moolenaar for (entry = funccal_stack; entry != NULL; entry = entry->next)
567220cc5283SBram Moolenaar for (fc = entry->top_funccal; fc != NULL; fc = fc->caller)
567320cc5283SBram Moolenaar if (set_ref_in_funccal(fc, copyID))
567420cc5283SBram Moolenaar return TRUE;
567520cc5283SBram Moolenaar return FALSE;
5676bc7ce675SBram Moolenaar }
5677bc7ce675SBram Moolenaar
5678bc7ce675SBram Moolenaar /*
5679bc7ce675SBram Moolenaar * Set "copyID" in all functions available by name.
5680bc7ce675SBram Moolenaar */
5681bc7ce675SBram Moolenaar int
set_ref_in_functions(int copyID)5682bc7ce675SBram Moolenaar set_ref_in_functions(int copyID)
5683a9b579f3SBram Moolenaar {
5684bc7ce675SBram Moolenaar int todo;
5685bc7ce675SBram Moolenaar hashitem_T *hi = NULL;
5686bc7ce675SBram Moolenaar ufunc_T *fp;
5687bc7ce675SBram Moolenaar
5688bc7ce675SBram Moolenaar todo = (int)func_hashtab.ht_used;
5689bc7ce675SBram Moolenaar for (hi = func_hashtab.ht_array; todo > 0 && !got_int; ++hi)
5690bc7ce675SBram Moolenaar {
5691bc7ce675SBram Moolenaar if (!HASHITEM_EMPTY(hi))
5692bc7ce675SBram Moolenaar {
5693bc7ce675SBram Moolenaar --todo;
5694bc7ce675SBram Moolenaar fp = HI2UF(hi);
569520cc5283SBram Moolenaar if (!func_name_refcount(fp->uf_name)
569620cc5283SBram Moolenaar && set_ref_in_func(NULL, fp, copyID))
569720cc5283SBram Moolenaar return TRUE;
5698bc7ce675SBram Moolenaar }
5699a9b579f3SBram Moolenaar }
570020cc5283SBram Moolenaar return FALSE;
5701a9b579f3SBram Moolenaar }
5702a9b579f3SBram Moolenaar
5703a9b579f3SBram Moolenaar /*
5704a9b579f3SBram Moolenaar * Set "copyID" in all function arguments.
5705a9b579f3SBram Moolenaar */
5706a9b579f3SBram Moolenaar int
set_ref_in_func_args(int copyID)5707a9b579f3SBram Moolenaar set_ref_in_func_args(int copyID)
5708a9b579f3SBram Moolenaar {
5709a9b579f3SBram Moolenaar int i;
5710a9b579f3SBram Moolenaar
5711a9b579f3SBram Moolenaar for (i = 0; i < funcargs.ga_len; ++i)
571220cc5283SBram Moolenaar if (set_ref_in_item(((typval_T **)funcargs.ga_data)[i],
571320cc5283SBram Moolenaar copyID, NULL, NULL))
571420cc5283SBram Moolenaar return TRUE;
571520cc5283SBram Moolenaar return FALSE;
5716a9b579f3SBram Moolenaar }
5717a9b579f3SBram Moolenaar
57181e96d9bfSBram Moolenaar /*
57191e96d9bfSBram Moolenaar * Mark all lists and dicts referenced through function "name" with "copyID".
57201e96d9bfSBram Moolenaar * Returns TRUE if setting references failed somehow.
57211e96d9bfSBram Moolenaar */
57221e96d9bfSBram Moolenaar int
set_ref_in_func(char_u * name,ufunc_T * fp_in,int copyID)5723437bafe4SBram Moolenaar set_ref_in_func(char_u *name, ufunc_T *fp_in, int copyID)
57241e96d9bfSBram Moolenaar {
5725437bafe4SBram Moolenaar ufunc_T *fp = fp_in;
57261e96d9bfSBram Moolenaar funccall_T *fc;
5727ef140544SBram Moolenaar int error = FCERR_NONE;
57281e96d9bfSBram Moolenaar char_u fname_buf[FLEN_FIXED + 1];
57291e96d9bfSBram Moolenaar char_u *tofree = NULL;
57301e96d9bfSBram Moolenaar char_u *fname;
5731bc7ce675SBram Moolenaar int abort = FALSE;
57321e96d9bfSBram Moolenaar
5733437bafe4SBram Moolenaar if (name == NULL && fp_in == NULL)
57341e96d9bfSBram Moolenaar return FALSE;
57351e96d9bfSBram Moolenaar
5736437bafe4SBram Moolenaar if (fp_in == NULL)
5737437bafe4SBram Moolenaar {
57381e96d9bfSBram Moolenaar fname = fname_trans_sid(name, fname_buf, &tofree, &error);
57394c17ad94SBram Moolenaar fp = find_func(fname, FALSE, NULL);
5740437bafe4SBram Moolenaar }
57411e96d9bfSBram Moolenaar if (fp != NULL)
57421e96d9bfSBram Moolenaar {
57431e96d9bfSBram Moolenaar for (fc = fp->uf_scoped; fc != NULL; fc = fc->func->uf_scoped)
5744bc7ce675SBram Moolenaar abort = abort || set_ref_in_funccal(fc, copyID);
57451e96d9bfSBram Moolenaar }
57465adc55cbSBram Moolenaar
57471e96d9bfSBram Moolenaar vim_free(tofree);
5748bc7ce675SBram Moolenaar return abort;
57491e96d9bfSBram Moolenaar }
57501e96d9bfSBram Moolenaar
5751e38eab22SBram Moolenaar #endif // FEAT_EVAL
5752