diff options
Diffstat (limited to '')
-rw-r--r-- | src/userfunc.c | 95 |
1 files changed, 93 insertions, 2 deletions
diff --git a/src/userfunc.c b/src/userfunc.c index 7536234..5d16710 100644 --- a/src/userfunc.c +++ b/src/userfunc.c @@ -2212,6 +2212,49 @@ find_func_with_prefix(char_u *name, int sid) } /* + * Find a function by name, return pointer to it. + * The name may be a local script variable, VAR_FUNC. or it may be a fully + * qualified import name such as 'i_imp.FuncName'. + * + * When VAR_FUNC, the import might either direct or autoload. + * When 'i_imp.FuncName' it is direct, autoload is rewritten as i_imp#FuncName + * in f_call and subsequently found. + */ + static ufunc_T * +find_func_imported(char_u *name, int flags) +{ + ufunc_T *func = NULL; + char_u *dot = name; // Find a dot, '.', in the name + + // Either run into '.' or the end of the string + while (eval_isnamec(*dot)) + ++dot; + + if (*dot == '.') + { + imported_T *import = find_imported(name, dot - name, FALSE); + if (import != NULL) + func = find_func_with_sid(dot + 1, import->imp_sid); + } + else if (*dot == NUL) // looking at the entire string + { + hashtab_T *ht = get_script_local_ht(); + if (ht != NULL) + { + hashitem_T *hi = hash_find(ht, name); + if (!HASHITEM_EMPTY(hi)) + { + dictitem_T *di = HI2DI(hi); + if (di->di_tv.v_type == VAR_FUNC + && di->di_tv.vval.v_string != NULL) + func = find_func_even_dead(di->di_tv.vval.v_string, flags); + } + } + } + return func; +} + +/* * Find a function by name, return pointer to it in ufuncs. * When "flags" has FFED_IS_GLOBAL don't find script-local or imported * functions. @@ -2260,8 +2303,15 @@ find_func_even_dead(char_u *name, int flags) } // Find autoload function if this is an autoload script. - return find_func_with_prefix(name[0] == 's' && name[1] == ':' + func = find_func_with_prefix(name[0] == 's' && name[1] == ':' ? name + 2 : name, current_sctx.sc_sid); + if (func != NULL) + return func; + + // Find a script-local "VAR_FUNC" or i_"imp.Func", so vim9script). + if (in_vim9script()) + func = find_func_imported(name, flags); + return func; } /* @@ -4009,7 +4059,7 @@ theend: int call_simple_func( char_u *funcname, // name of the function - int len, // length of "name" or -1 to use strlen() + size_t len, // length of "name" typval_T *rettv) // return value goes here { int ret = FAIL; @@ -5503,6 +5553,47 @@ ex_function(exarg_T *eap) ga_clear_strings(&lines_to_free); } + int +get_func_arity(char_u *name, int *required, int *optional, int *varargs) +{ + ufunc_T *ufunc = NULL; + int argcount = 0; + int min_argcount = 0; + int idx; + + idx = find_internal_func(name); + if (idx >= 0) + { + internal_func_get_argcount(idx, &argcount, &min_argcount); + *varargs = FALSE; + } + else + { + char_u fname_buf[FLEN_FIXED + 1]; + char_u *tofree = NULL; + funcerror_T error = FCERR_NONE; + char_u *fname; + + // May need to translate <SNR>123_ to K_SNR. + fname = fname_trans_sid(name, fname_buf, &tofree, &error); + if (error == FCERR_NONE) + ufunc = find_func(fname, FALSE); + vim_free(tofree); + + if (ufunc == NULL) + return FAIL; + + argcount = ufunc->uf_args.ga_len; + min_argcount = ufunc->uf_args.ga_len - ufunc->uf_def_args.ga_len; + *varargs = has_varargs(ufunc); + } + + *required = min_argcount; + *optional = argcount - min_argcount; + + return OK; +} + /* * Find a function by name, including "<lambda>123". * Check for "profile" and "debug" arguments and set"compile_type". |