aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/eval/userfunc.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/eval/userfunc.c')
-rw-r--r--src/nvim/eval/userfunc.c623
1 files changed, 332 insertions, 291 deletions
diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c
index 5ffc06ec44..657777d7db 100644
--- a/src/nvim/eval/userfunc.c
+++ b/src/nvim/eval/userfunc.c
@@ -5,6 +5,7 @@
#include "nvim/ascii.h"
#include "nvim/charset.h"
+#include "nvim/debugger.h"
#include "nvim/edit.h"
#include "nvim/eval.h"
#include "nvim/eval/encode.h"
@@ -12,7 +13,6 @@
#include "nvim/ex_cmds2.h"
#include "nvim/ex_docmd.h"
#include "nvim/ex_getln.h"
-#include "nvim/ex_getln.h"
#include "nvim/fileio.h"
#include "nvim/getchar.h"
#include "nvim/globals.h"
@@ -39,7 +39,7 @@
#define FC_CFUNC 0x800 // C function extension
#ifdef INCLUDE_GENERATED_DECLARATIONS
-#include "eval/userfunc.c.generated.h"
+# include "eval/userfunc.c.generated.h"
#endif
hashtab_T func_hashtab;
@@ -54,26 +54,25 @@ static funccall_T *current_funccal = NULL;
// item in it is still being used.
static funccall_T *previous_funccal = NULL;
-static char *e_funcexts = N_(
- "E122: Function %s already exists, add ! to replace it");
+static char *e_funcexts = N_("E122: Function %s already exists, add ! to replace it");
static char *e_funcdict = N_("E717: Dictionary entry already exists");
static char *e_funcref = N_("E718: Funcref required");
static char *e_nofunc = N_("E130: Unknown function: %s");
void func_init(void)
{
- hash_init(&func_hashtab);
+ hash_init(&func_hashtab);
}
/// Get function arguments.
-static int get_function_args(char_u **argp, char_u endchar, garray_T *newargs,
- int *varargs, garray_T *default_args, bool skip)
+static int get_function_args(char_u **argp, char_u endchar, garray_T *newargs, int *varargs,
+ garray_T *default_args, bool skip)
{
- bool mustend = false;
- char_u *arg = *argp;
- char_u *p = arg;
- int c;
- int i;
+ bool mustend = false;
+ char_u *arg = *argp;
+ char_u *p = arg;
+ int c;
+ int i;
if (newargs != NULL) {
ga_init(newargs, (int)sizeof(char_u *), 3);
@@ -145,7 +144,7 @@ static int get_function_args(char_u **argp, char_u endchar, garray_T *newargs,
*p = NUL;
expr = vim_strsave(expr);
((char_u **)(default_args->ga_data))
- [default_args->ga_len] = expr;
+ [default_args->ga_len] = expr;
default_args->ga_len++;
*p = c;
} else {
@@ -199,18 +198,18 @@ static void register_closure(ufunc_T *fp)
current_funccal->fc_refcount++;
ga_grow(&current_funccal->fc_funcs, 1);
((ufunc_T **)current_funccal->fc_funcs.ga_data)
- [current_funccal->fc_funcs.ga_len++] = fp;
+ [current_funccal->fc_funcs.ga_len++] = fp;
}
/// Get a name for a lambda. Returned in static memory.
-char_u * get_lambda_name(void)
+char_u *get_lambda_name(void)
{
- static char_u name[30];
- static int lambda_no = 0;
+ static char_u name[30];
+ static int lambda_no = 0;
- snprintf((char *)name, sizeof(name), "<lambda>%d", ++lambda_no);
- return name;
+ snprintf((char *)name, sizeof(name), "<lambda>%d", ++lambda_no);
+ return name;
}
/// Parse a lambda expression and get a Funcref from "*arg".
@@ -218,16 +217,16 @@ char_u * get_lambda_name(void)
/// @return OK or FAIL. Returns NOTDONE for dict or {expr}.
int get_lambda_tv(char_u **arg, typval_T *rettv, bool evaluate)
{
- garray_T newargs = GA_EMPTY_INIT_VALUE;
- garray_T *pnewargs;
- ufunc_T *fp = NULL;
+ garray_T newargs = GA_EMPTY_INIT_VALUE;
+ garray_T *pnewargs;
+ ufunc_T *fp = NULL;
partial_T *pt = NULL;
- int varargs;
- int ret;
- char_u *start = skipwhite(*arg + 1);
- char_u *s, *e;
- bool *old_eval_lavars = eval_lavars_used;
- bool eval_lavars = false;
+ int varargs;
+ int ret;
+ char_u *start = skipwhite(*arg + 1);
+ char_u *s, *e;
+ bool *old_eval_lavars = eval_lavars_used;
+ bool eval_lavars = false;
// First, check if this is a lambda expression. "->" must exists.
ret = get_function_args(&start, '-', NULL, NULL, NULL, true);
@@ -347,8 +346,7 @@ errret:
/// was not found.
///
/// @return name of the function.
-char_u *deref_func_name(const char *name, int *lenp,
- partial_T **const partialp, bool no_autoload)
+char_u *deref_func_name(const char *name, int *lenp, partial_T **const partialp, bool no_autoload)
FUNC_ATTR_NONNULL_ARG(1, 2)
{
if (partialp != NULL) {
@@ -408,46 +406,41 @@ void emsg_funcname(char *ermsg, const char_u *name)
* Allocate a variable for the result of a function.
* Return OK or FAIL.
*/
-int
-get_func_tv(
- const char_u *name, // name of the function
- int len, // length of "name" or -1 to use strlen()
- typval_T *rettv,
- char_u **arg, // argument, pointing to the '('
- linenr_T firstline, // first line of range
- linenr_T lastline, // last line of range
- int *doesrange, // return: function handled range
- int evaluate,
- partial_T *partial, // for extra arguments
- dict_T *selfdict // Dictionary for "self"
-)
-{
- char_u *argp;
+int get_func_tv(const char_u *name, // name of the function
+ int len, // length of "name" or -1 to use strlen()
+ typval_T *rettv, char_u **arg, // argument, pointing to the '('
+ funcexe_T *funcexe // various values
+ )
+{
+ char_u *argp;
int ret = OK;
- typval_T argvars[MAX_FUNC_ARGS + 1]; /* vars for arguments */
- int argcount = 0; /* number of arguments found */
+ typval_T argvars[MAX_FUNC_ARGS + 1]; // vars for arguments
+ int argcount = 0; // number of arguments found
/*
* Get the arguments.
*/
argp = *arg;
- while (argcount < MAX_FUNC_ARGS - (partial == NULL ? 0 : partial->pt_argc)) {
+ while (argcount < MAX_FUNC_ARGS
+ - (funcexe->partial == NULL ? 0 : funcexe->partial->pt_argc)) {
argp = skipwhite(argp + 1); // skip the '(' or ','
if (*argp == ')' || *argp == ',' || *argp == NUL) {
break;
}
- if (eval1(&argp, &argvars[argcount], evaluate) == FAIL) {
+ if (eval1(&argp, &argvars[argcount], funcexe->evaluate) == FAIL) {
ret = FAIL;
break;
}
++argcount;
- if (*argp != ',')
+ if (*argp != ',') {
break;
+ }
}
- if (*argp == ')')
+ if (*argp == ')') {
++argp;
- else
+ } else {
ret = FAIL;
+ }
if (ret == OK) {
int i = 0;
@@ -463,9 +456,7 @@ get_func_tv(
((typval_T **)funcargs.ga_data)[funcargs.ga_len++] = &argvars[i];
}
}
- ret = call_func(name, len, rettv, argcount, argvars, NULL,
- firstline, lastline, doesrange, evaluate,
- partial, selfdict);
+ ret = call_func(name, len, rettv, argcount, argvars, funcexe);
funcargs.ga_len -= i;
} else if (!aborting()) {
@@ -517,8 +508,7 @@ static inline bool eval_fname_sid(const char *const name)
///
/// @return transformed name: either `fname_buf` or a pointer to an allocated
/// memory.
-static char_u *fname_trans_sid(const char_u *const name,
- char_u *const fname_buf,
+static char_u *fname_trans_sid(const char_u *const name, char_u *const fname_buf,
char_u **const tofree, int *const error)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
@@ -558,11 +548,12 @@ static char_u *fname_trans_sid(const char_u *const name,
/// @return NULL for unknown function.
ufunc_T *find_func(const char_u *name)
{
- hashitem_T *hi;
+ hashitem_T *hi;
hi = hash_find(&func_hashtab, name);
- if (!HASHITEM_EMPTY(hi))
+ if (!HASHITEM_EMPTY(hi)) {
return HI2UF(hi);
+ }
return NULL;
}
@@ -576,8 +567,9 @@ static void cat_func_name(char_u *buf, ufunc_T *fp)
if (fp->uf_name[0] == K_SPECIAL) {
STRCPY(buf, "<SNR>");
STRCAT(buf, fp->uf_name + 3);
- } else
+ } else {
STRCPY(buf, fp->uf_name);
+ }
}
/*
@@ -667,7 +659,6 @@ static void cleanup_function_call(funccall_T *fc)
if (may_free_fc && fc->l_varlist.lv_refcount // NOLINT(runtime/deprecated)
== DO_NOT_FREE_CNT) {
fc->l_varlist.lv_first = NULL; // NOLINT(runtime/deprecated)
-
} else {
free_fc = false;
@@ -812,23 +803,22 @@ static void func_clear_free(ufunc_T *fp, bool force)
/// @param[in] firstline First line of range.
/// @param[in] lastline Last line of range.
/// @param selfdict Dictionary for "self" for dictionary functions.
-void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars,
- typval_T *rettv, linenr_T firstline, linenr_T lastline,
- dict_T *selfdict)
+void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rettv,
+ linenr_T firstline, linenr_T lastline, dict_T *selfdict)
FUNC_ATTR_NONNULL_ARG(1, 3, 4)
{
- char_u *save_sourcing_name;
+ char_u *save_sourcing_name;
linenr_T save_sourcing_lnum;
bool using_sandbox = false;
- funccall_T *fc;
+ funccall_T *fc;
int save_did_emsg;
static int depth = 0;
- dictitem_T *v;
+ dictitem_T *v;
int fixvar_idx = 0; // index in fixvar[]
int ai;
bool islambda = false;
char_u numbuf[NUMBUFLEN];
- char_u *name;
+ char_u *name;
typval_T *tv_to_free[MAX_FUNC_ARGS];
int tv_to_free_len = 0;
proftime_T wait_start;
@@ -954,7 +944,7 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars,
def_rettv.vval.v_number = -1;
default_expr = ((char_u **)(fp->uf_def_args.ga_data))
- [ai + fp->uf_def_args.ga_len];
+ [ai + fp->uf_def_args.ga_len];
if (eval1(&default_expr, &def_rettv, true) == FAIL) {
default_arg_err = true;
break;
@@ -1140,7 +1130,7 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars,
call_start = profile_sub_wait(wait_start, call_start); // -V614
fp->uf_tm_total = profile_add(fp->uf_tm_total, call_start);
fp->uf_tm_self = profile_self(fp->uf_tm_self, call_start,
- fp->uf_tm_children);
+ fp->uf_tm_children);
if (fc->caller != NULL && fc->caller->func->uf_profiling) {
fc->caller->func->uf_tm_children =
profile_add(fc->caller->func->uf_tm_children, call_start);
@@ -1158,19 +1148,19 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars,
++no_wait_return;
verbose_enter_scroll();
- if (aborting())
+ if (aborting()) {
smsg(_("%s aborted"), sourcing_name);
- else if (fc->rettv->v_type == VAR_NUMBER)
+ } else if (fc->rettv->v_type == VAR_NUMBER) {
smsg(_("%s returning #%" PRId64 ""),
sourcing_name, (int64_t)fc->rettv->vval.v_number);
- else {
+ } else {
char_u buf[MSG_BUF_LEN];
// The value may be very long. Skip the middle part, so that we
// have some idea how it starts and ends. smsg() would always
// truncate it at the end. Don't want errors such as E724 here.
emsg_off++;
- char_u *s = (char_u *) encode_tv2string(fc->rettv, NULL);
+ char_u *s = (char_u *)encode_tv2string(fc->rettv, NULL);
char_u *tofree = s;
emsg_off--;
if (s != NULL) {
@@ -1274,8 +1264,8 @@ void set_current_funccal(funccall_T *fc)
#if defined(EXITFREE)
void free_all_functions(void)
{
- hashitem_T *hi;
- ufunc_T *fp;
+ hashitem_T *hi;
+ ufunc_T *fp;
uint64_t skipped = 0;
uint64_t todo = 1;
uint64_t used;
@@ -1362,12 +1352,10 @@ static bool builtin_function(const char *name, int len)
return p == NULL;
}
-int func_call(char_u *name, typval_T *args, partial_T *partial,
- dict_T *selfdict, typval_T *rettv)
+int func_call(char_u *name, typval_T *args, partial_T *partial, dict_T *selfdict, typval_T *rettv)
{
typval_T argv[MAX_FUNC_ARGS + 1];
int argc = 0;
- int dummy;
int r = 0;
TV_LIST_ITER(args->vval.v_list, item, {
@@ -1380,9 +1368,13 @@ int func_call(char_u *name, typval_T *args, partial_T *partial,
tv_copy(TV_LIST_ITEM_TV(item), &argv[argc++]);
});
- r = call_func(name, -1, rettv, argc, argv, NULL,
- curwin->w_cursor.lnum, curwin->w_cursor.lnum,
- &dummy, true, partial, selfdict);
+ funcexe_T funcexe = FUNCEXE_INIT;
+ funcexe.firstline = curwin->w_cursor.lnum;
+ funcexe.lastline = curwin->w_cursor.lnum;
+ funcexe.evaluate = true;
+ funcexe.partial = partial;
+ funcexe.selfdict = selfdict;
+ r = call_func(name, -1, rettv, argc, argv, &funcexe);
func_call_skip_call:
// Free the arguments.
@@ -1399,56 +1391,63 @@ static void user_func_error(int error, const char_u *name)
FUNC_ATTR_NONNULL_ALL
{
switch (error) {
- case ERROR_UNKNOWN:
- emsg_funcname(N_("E117: Unknown function: %s"), name);
- break;
- case ERROR_DELETED:
- emsg_funcname(N_("E933: Function was deleted: %s"), name);
- break;
- case ERROR_TOOMANY:
- emsg_funcname(_(e_toomanyarg), name);
- break;
- case ERROR_TOOFEW:
- emsg_funcname(N_("E119: Not enough arguments for function: %s"),
- name);
- break;
- case ERROR_SCRIPT:
- emsg_funcname(N_("E120: Using <SID> not in a script context: %s"),
- name);
- break;
- case ERROR_DICT:
- emsg_funcname(N_("E725: Calling dict function without Dictionary: %s"),
- name);
- break;
+ case ERROR_UNKNOWN:
+ emsg_funcname(N_("E117: Unknown function: %s"), name);
+ break;
+ case ERROR_NOTMETHOD:
+ emsg_funcname(N_("E276: Cannot use function as a method: %s"), name);
+ break;
+ case ERROR_DELETED:
+ emsg_funcname(N_("E933: Function was deleted: %s"), name);
+ break;
+ case ERROR_TOOMANY:
+ emsg_funcname(_(e_toomanyarg), name);
+ break;
+ case ERROR_TOOFEW:
+ emsg_funcname(N_("E119: Not enough arguments for function: %s"),
+ name);
+ break;
+ case ERROR_SCRIPT:
+ emsg_funcname(N_("E120: Using <SID> not in a script context: %s"),
+ name);
+ break;
+ case ERROR_DICT:
+ emsg_funcname(N_("E725: Calling dict function without Dictionary: %s"),
+ name);
+ break;
+ }
+}
+
+/// Used by call_func to add a method base (if any) to a function argument list
+/// as the first argument. @see call_func
+static void argv_add_base(typval_T *const basetv, typval_T **const argvars, int *const argcount,
+ typval_T *const new_argvars, int *const argv_base)
+ FUNC_ATTR_NONNULL_ARG(2, 3, 4, 5)
+{
+ if (basetv != NULL) {
+ // Method call: base->Method()
+ memmove(&new_argvars[1], *argvars, sizeof(typval_T) * (*argcount));
+ new_argvars[0] = *basetv;
+ (*argcount)++;
+ *argvars = new_argvars;
+ *argv_base = 1;
}
}
/// Call a function with its resolved parameters
///
-/// "argv_func", when not NULL, can be used to fill in arguments only when the
-/// invoked function uses them. It is called like this:
-/// new_argcount = argv_func(current_argcount, argv, called_func_argcount)
-///
/// @return FAIL if function cannot be called, else OK (even if an error
/// occurred while executing the function! Set `msg_list` to capture
/// the error, see do_cmdline()).
-int
-call_func(
- const char_u *funcname, // name of the function
- int len, // length of "name" or -1 to use strlen()
- typval_T *rettv, // [out] value goes here
- int argcount_in, // number of "argvars"
- typval_T *argvars_in, // vars for arguments, must have "argcount"
- // PLUS ONE elements!
- ArgvFunc argv_func, // function to fill in argvars
- linenr_T firstline, // first line of range
- linenr_T lastline, // last line of range
- int *doesrange, // [out] function handled range
- bool evaluate,
- partial_T *partial, // optional, can be NULL
- dict_T *selfdict_in // Dictionary for "self"
-)
- FUNC_ATTR_NONNULL_ARG(1, 3, 5, 9)
+int call_func(const char_u *funcname, // name of the function
+ int len, // length of "name" or -1 to use strlen()
+ typval_T *rettv, // [out] value goes here
+ int argcount_in, // number of "argvars"
+ typval_T *argvars_in, // vars for arguments, must have "argcount"
+ // PLUS ONE elements!
+ funcexe_T *funcexe // more arguments
+ )
+ FUNC_ATTR_NONNULL_ARG(1, 3, 5, 6)
{
int ret = FAIL;
int error = ERROR_NONE;
@@ -1459,9 +1458,12 @@ call_func(
char_u *name = NULL;
int argcount = argcount_in;
typval_T *argvars = argvars_in;
- dict_T *selfdict = selfdict_in;
- typval_T argv[MAX_FUNC_ARGS + 1]; // used when "partial" is not NULL
+ dict_T *selfdict = funcexe->selfdict;
+ typval_T argv[MAX_FUNC_ARGS + 1]; // used when "partial" or
+ // "funcexe->basetv" is not NULL
int argv_clear = 0;
+ int argv_base = 0;
+ partial_T *partial = funcexe->partial;
// Initialize rettv so that it is safe for caller to invoke clear_tv(rettv)
// even when call_func() returns FAIL.
@@ -1480,14 +1482,15 @@ call_func(
fname = fname_trans_sid(name, fname_buf, &tofree, &error);
}
- *doesrange = false;
+ if (funcexe->doesrange != NULL) {
+ *funcexe->doesrange = false;
+ }
if (partial != NULL) {
// When the function has a partial with a dict and there is a dict
// argument, use the dict argument. That is backwards compatible.
// When the dict was bound explicitly use the one from the partial.
- if (partial->pt_dict != NULL
- && (selfdict_in == NULL || !partial->pt_auto)) {
+ if (partial->pt_dict != NULL && (selfdict == NULL || !partial->pt_auto)) {
selfdict = partial->pt_dict;
}
if (error == ERROR_NONE && partial->pt_argc > 0) {
@@ -1506,7 +1509,7 @@ call_func(
}
}
- if (error == ERROR_NONE && evaluate) {
+ if (error == ERROR_NONE && funcexe->evaluate) {
char_u *rfname = fname;
// Ignore "g:" before a function name.
@@ -1521,7 +1524,12 @@ call_func(
if (is_luafunc(partial)) {
if (len > 0) {
error = ERROR_NONE;
+ argv_add_base(funcexe->basetv, &argvars, &argcount, argv, &argv_base);
nlua_typval_call((const char *)funcname, len, argvars, argcount, rettv);
+ } else {
+ // v:lua was called directly; show its name in the emsg
+ XFREE_CLEAR(name);
+ funcname = (const char_u *)"v:lua";
}
} else if (fp != NULL || !builtin_function((const char *)rfname, -1)) {
// User defined function.
@@ -1531,7 +1539,7 @@ call_func(
// Trigger FuncUndefined event, may load the function.
if (fp == NULL
- && apply_autocmds(EVENT_FUNCUNDEFINED, rfname, rfname, TRUE, NULL)
+ && apply_autocmds(EVENT_FUNCUNDEFINED, rfname, rfname, true, NULL)
&& !aborting()) {
// executed an autocommand, search for the function again
fp = find_func(rfname);
@@ -1549,13 +1557,16 @@ call_func(
cfunc_T cb = fp->uf_cb;
error = (*cb)(argcount, argvars, rettv, fp->uf_cb_state);
} else if (fp != NULL) {
- if (argv_func != NULL) {
+ if (funcexe->argv_func != NULL) {
// postponed filling in the arguments, do it now
- argcount = argv_func(argcount, argvars, argv_clear,
- fp->uf_args.ga_len);
+ argcount = funcexe->argv_func(argcount, argvars, argv_clear,
+ fp->uf_args.ga_len);
}
- if (fp->uf_flags & FC_RANGE) {
- *doesrange = true;
+
+ argv_add_base(funcexe->basetv, &argvars, &argcount, argv, &argv_base);
+
+ if (fp->uf_flags & FC_RANGE && funcexe->doesrange != NULL) {
+ *funcexe->doesrange = true;
}
if (argcount < fp->uf_args.ga_len - fp->uf_def_args.ga_len) {
error = ERROR_TOOFEW;
@@ -1565,25 +1576,20 @@ call_func(
error = ERROR_DICT;
} else {
// Call the user function.
- call_user_func(fp, argcount, argvars, rettv, firstline, lastline,
+ call_user_func(fp, argcount, argvars, rettv, funcexe->firstline,
+ funcexe->lastline,
(fp->uf_flags & FC_DICT) ? selfdict : NULL);
error = ERROR_NONE;
}
}
+ } else if (funcexe->basetv != NULL) {
+ // expr->method(): Find the method name in the table, call its
+ // implementation with the base as one of the arguments.
+ error = call_internal_method(fname, argcount, argvars, rettv,
+ funcexe->basetv);
} else {
// Find the function name in the table, call its implementation.
- const VimLFuncDef *const fdef = find_internal_func((const char *)fname);
- if (fdef != NULL) {
- if (argcount < fdef->min_argc) {
- error = ERROR_TOOFEW;
- } else if (argcount > fdef->max_argc) {
- error = ERROR_TOOMANY;
- } else {
- argvars[argcount].v_type = VAR_UNKNOWN;
- fdef->func(argvars, rettv, fdef->data);
- error = ERROR_NONE;
- }
- }
+ error = call_internal_func(fname, argcount, argvars, rettv);
}
/*
* The function call (or "FuncUndefined" autocommand sequence) might
@@ -1597,8 +1603,9 @@ call_func(
*/
update_force_abort();
}
- if (error == ERROR_NONE)
+ if (error == ERROR_NONE) {
ret = OK;
+ }
theend:
// Report an error unless the argument evaluation or function call has been
@@ -1607,9 +1614,11 @@ theend:
user_func_error(error, (name != NULL) ? name : funcname);
}
+ // clear the copies made from the partial
while (argv_clear > 0) {
- tv_clear(&argv[--argv_clear]);
+ tv_clear(&argv[--argv_clear + argv_base]);
}
+
xfree(tofree);
xfree(name);
@@ -1624,8 +1633,9 @@ theend:
static void list_func_head(ufunc_T *fp, int indent, bool force)
{
msg_start();
- if (indent)
+ if (indent) {
MSG_PUTS(" ");
+ }
MSG_PUTS(force ? "function! " : "function ");
if (fp->uf_name[0] == K_SPECIAL) {
MSG_PUTS_ATTR("<SNR>", HL_ATTR(HLF_8));
@@ -1681,25 +1691,22 @@ static void list_func_head(ufunc_T *fp, int indent, bool force)
/// Advances "pp" to just after the function name (if no error).
///
/// @return the function name in allocated memory, or NULL for failure.
-char_u *
-trans_function_name(
- char_u **pp,
- bool skip, // only find the end, don't evaluate
- int flags,
- funcdict_T *fdp, // return: info about dictionary used
- partial_T **partial // return: partial of a FuncRef
-)
+char_u *trans_function_name(char_u **pp, bool skip, // only find the end, don't evaluate
+ int flags, funcdict_T *fdp, // return: info about dictionary used
+ partial_T **partial // return: partial of a FuncRef
+ )
FUNC_ATTR_NONNULL_ARG(1)
{
- char_u *name = NULL;
+ char_u *name = NULL;
const char_u *start;
const char_u *end;
int lead;
int len;
lval_T lv;
- if (fdp != NULL)
+ if (fdp != NULL) {
memset(fdp, 0, sizeof(funcdict_T));
+ }
start = *pp;
/* Check for hard coded <SNR>: already translated function ID (from a user
@@ -1722,8 +1729,9 @@ trans_function_name(
end = get_lval((char_u *)start, NULL, &lv, false, skip, flags | GLV_READ_ONLY,
lead > 2 ? 0 : FNE_CHECK_START);
if (end == start) {
- if (!skip)
+ if (!skip) {
EMSG(_("E129: Function name required"));
+ }
goto theend;
}
if (end == NULL || (lv.ll_tv != NULL && (lead > 2 || lv.ll_range))) {
@@ -1789,7 +1797,7 @@ trans_function_name(
goto theend;
}
- /* Check if the name is a Funcref. If so, use the value. */
+ // Check if the name is a Funcref. If so, use the value.
if (lv.ll_exp_name != NULL) {
len = (int)strlen(lv.ll_exp_name);
name = deref_func_name(lv.ll_exp_name, &len, partial,
@@ -1898,31 +1906,31 @@ theend:
*/
void ex_function(exarg_T *eap)
{
- char_u *theline;
- char_u *line_to_free = NULL;
+ char_u *theline;
+ char_u *line_to_free = NULL;
int c;
int saved_did_emsg;
- int saved_wait_return = need_wait_return;
- char_u *name = NULL;
- char_u *p;
- char_u *arg;
- char_u *line_arg = NULL;
+ bool saved_wait_return = need_wait_return;
+ char_u *name = NULL;
+ char_u *p;
+ char_u *arg;
+ char_u *line_arg = NULL;
garray_T newargs;
garray_T default_args;
garray_T newlines;
int varargs = false;
int flags = 0;
- ufunc_T *fp;
+ ufunc_T *fp;
bool overwrite = false;
int indent;
int nesting;
- dictitem_T *v;
+ dictitem_T *v;
funcdict_T fudi;
static int func_nr = 0; // number for nameless function
int paren;
- hashtab_T *ht;
+ hashtab_T *ht;
int todo;
- hashitem_T *hi;
+ hashitem_T *hi;
linenr_T sourcing_lnum_off;
linenr_T sourcing_lnum_top;
bool is_heredoc = false;
@@ -1975,15 +1983,17 @@ void ex_function(exarg_T *eap)
--todo;
fp = HI2UF(hi);
if (!isdigit(*fp->uf_name)
- && vim_regexec(&regmatch, fp->uf_name, 0))
+ && vim_regexec(&regmatch, fp->uf_name, 0)) {
list_func_head(fp, false, false);
+ }
}
}
vim_regfree(regmatch.regprog);
}
}
- if (*p == '/')
+ if (*p == '/') {
++p;
+ }
eap->nextcmd = check_nextcmd(p);
return;
}
@@ -2017,8 +2027,9 @@ void ex_function(exarg_T *eap)
}
xfree(fudi.fd_newkey);
return;
- } else
+ } else {
eap->skip = TRUE;
+ }
}
/* An error in a function call during evaluation of an expression in magic
@@ -2038,8 +2049,9 @@ void ex_function(exarg_T *eap)
goto ret_free;
}
eap->nextcmd = check_nextcmd(p);
- if (eap->nextcmd != NULL)
+ if (eap->nextcmd != NULL) {
*p = NUL;
+ }
if (!eap->skip && !got_int) {
fp = find_func(name);
if (fp != NULL) {
@@ -2066,8 +2078,9 @@ void ex_function(exarg_T *eap)
msg_putchar('\n');
msg_puts(eap->forceit ? "endfunction" : " endfunction");
}
- } else
+ } else {
emsg_funcname(N_("E123: Undefined function: %s"), name);
+ }
}
goto ret_free;
}
@@ -2094,17 +2107,20 @@ void ex_function(exarg_T *eap)
if (!eap->skip) {
/* Check the name of the function. Unless it's a dictionary function
* (that we are overwriting). */
- if (name != NULL)
+ if (name != NULL) {
arg = name;
- else
+ } else {
arg = fudi.fd_newkey;
+ }
if (arg != NULL && (fudi.fd_di == NULL || !tv_is_func(fudi.fd_di->di_tv))) {
int j = (*arg == K_SPECIAL) ? 3 : 0;
while (arg[j] != NUL && (j == 0 ? eval_isnamec1(arg[j])
- : eval_isnamec(arg[j])))
+ : eval_isnamec(arg[j]))) {
++j;
- if (arg[j] != NUL)
+ }
+ if (arg[j] != NUL) {
emsg_funcname((char *)e_invarg2, arg);
+ }
}
// Disallow using the g: dict.
if (fudi.fd_dict != NULL && fudi.fd_dict->dv_scope == VAR_DEF_SCOPE) {
@@ -2139,7 +2155,7 @@ void ex_function(exarg_T *eap)
p += 7;
if (current_funccal == NULL) {
emsg_funcname(N_
- ("E932: Closure function should not be at top level: %s"),
+ ("E932: Closure function should not be at top level: %s"),
name == NULL ? (char_u *)"" : name);
goto erret;
}
@@ -2164,14 +2180,16 @@ void ex_function(exarg_T *eap)
* whole function before telling him it doesn't work! For a script we
* need to skip the body to be able to find what follows. */
if (!eap->skip && !eap->forceit) {
- if (fudi.fd_dict != NULL && fudi.fd_newkey == NULL)
+ if (fudi.fd_dict != NULL && fudi.fd_newkey == NULL) {
EMSG(_(e_funcdict));
- else if (name != NULL && find_func(name) != NULL)
+ } else if (name != NULL && find_func(name) != NULL) {
emsg_funcname(e_funcexts, name);
+ }
}
- if (!eap->skip && did_emsg)
+ if (!eap->skip && did_emsg) {
goto erret;
+ }
if (!ui_has(kUICmdline)) {
msg_putchar('\n'); // don't overwrite the function name
@@ -2195,9 +2213,9 @@ void ex_function(exarg_T *eap)
// Use eap->arg, split up in parts by line breaks.
theline = line_arg;
p = vim_strchr(theline, '\n');
- if (p == NULL)
+ if (p == NULL) {
line_arg += STRLEN(line_arg);
- else {
+ } else {
*p = NUL;
line_arg = p + 1;
}
@@ -2225,7 +2243,7 @@ void ex_function(exarg_T *eap)
// Detect line continuation: sourcing_lnum increased more than one.
sourcing_lnum_off = get_sourced_lnum(eap->getline, eap->cookie);
if (sourcing_lnum < sourcing_lnum_off) {
- sourcing_lnum_off -= sourcing_lnum;
+ sourcing_lnum_off -= sourcing_lnum;
} else {
sourcing_lnum_off = 0;
}
@@ -2289,13 +2307,14 @@ void ex_function(exarg_T *eap)
/* Increase indent inside "if", "while", "for" and "try", decrease
* at "end". */
- if (indent > 2 && STRNCMP(p, "end", 3) == 0)
+ if (indent > 2 && STRNCMP(p, "end", 3) == 0) {
indent -= 2;
- else if (STRNCMP(p, "if", 2) == 0
- || STRNCMP(p, "wh", 2) == 0
- || STRNCMP(p, "for", 3) == 0
- || STRNCMP(p, "try", 3) == 0)
+ } else if (STRNCMP(p, "if", 2) == 0
+ || STRNCMP(p, "wh", 2) == 0
+ || STRNCMP(p, "for", 3) == 0
+ || STRNCMP(p, "try", 3) == 0) {
indent += 2;
+ }
// Check for defining a function inside this function.
if (checkforcmd(&p, "function", 2)) {
@@ -2345,10 +2364,11 @@ void ex_function(exarg_T *eap)
&& (!ASCII_ISALPHA(p[2]) || p[2] == 's')))) {
// ":python <<" continues until a dot, like ":append"
p = skipwhite(arg + 2);
- if (*p == NUL)
+ if (*p == NUL) {
skip_until = vim_strsave((char_u *)".");
- else
+ } else {
skip_until = vim_strsave(p);
+ }
}
// Check for ":let v =<< [trim] EOF"
@@ -2391,8 +2411,9 @@ void ex_function(exarg_T *eap)
/* Add NULL lines for continuation lines, so that the line count is
* equal to the index in the growarray. */
- while (sourcing_lnum_off-- > 0)
+ while (sourcing_lnum_off-- > 0) {
((char_u **)(newlines.ga_data))[newlines.ga_len++] = NULL;
+ }
// Check for end of eap->arg.
if (line_arg != NULL && *line_arg == NUL) {
@@ -2402,8 +2423,9 @@ void ex_function(exarg_T *eap)
/* Don't define the function when skipping commands or when an error was
* detected. */
- if (eap->skip || did_emsg)
+ if (eap->skip || did_emsg) {
goto erret;
+ }
/*
* If there are no errors, add the function
@@ -2412,7 +2434,7 @@ void ex_function(exarg_T *eap)
v = find_var((const char *)name, STRLEN(name), &ht, false);
if (v != NULL && v->di_tv.v_type == VAR_FUNC) {
emsg_funcname(N_("E707: Function name conflicts with variable: %s"),
- name);
+ name);
goto erret;
}
@@ -2428,7 +2450,7 @@ void ex_function(exarg_T *eap)
}
if (fp->uf_calls > 0) {
emsg_funcname(N_("E127: Cannot redefine function %s: It is in use"),
- name);
+ name);
goto erret;
}
if (fp->uf_refcount > 1) {
@@ -2476,7 +2498,7 @@ void ex_function(exarg_T *eap)
if (fp == NULL) {
if (fudi.fd_dict == NULL && vim_strchr(name, AUTOLOAD_CHAR) != NULL) {
int slen, plen;
- char_u *scriptname;
+ char_u *scriptname;
// Check that the autoload name matches the script name.
int j = FAIL;
@@ -2486,14 +2508,14 @@ void ex_function(exarg_T *eap)
plen = (int)STRLEN(p);
slen = (int)STRLEN(sourcing_name);
if (slen > plen && fnamecmp(p,
- sourcing_name + slen - plen) == 0)
+ sourcing_name + slen - plen) == 0) {
j = OK;
+ }
xfree(scriptname);
}
if (j == FAIL) {
- EMSG2(_(
- "E746: Function name does not match script file name: %s"),
- name);
+ EMSG2(_("E746: Function name does not match script file name: %s"),
+ name);
goto erret;
}
}
@@ -2634,8 +2656,8 @@ bool function_exists(const char *const name, bool no_deref)
char_u *get_user_func_name(expand_T *xp, int idx)
{
static size_t done;
- static hashitem_T *hi;
- ufunc_T *fp;
+ static hashitem_T *hi;
+ ufunc_T *fp;
if (idx == 0) {
done = 0;
@@ -2643,10 +2665,12 @@ char_u *get_user_func_name(expand_T *xp, int idx)
}
assert(hi);
if (done < func_hashtab.ht_used) {
- if (done++ > 0)
+ if (done++ > 0) {
++hi;
- while (HASHITEM_EMPTY(hi))
+ }
+ while (HASHITEM_EMPTY(hi)) {
++hi;
+ }
fp = HI2UF(hi);
if ((fp->uf_flags & FC_DICT)
@@ -2661,8 +2685,9 @@ char_u *get_user_func_name(expand_T *xp, int idx)
cat_func_name(IObuff, fp);
if (xp->xp_context != EXPAND_USER_FUNC) {
STRCAT(IObuff, "(");
- if (!fp->uf_varargs && GA_EMPTY(&fp->uf_args))
+ if (!fp->uf_varargs && GA_EMPTY(&fp->uf_args)) {
STRCAT(IObuff, ")");
+ }
}
return IObuff;
}
@@ -2672,17 +2697,18 @@ char_u *get_user_func_name(expand_T *xp, int idx)
/// ":delfunction {name}"
void ex_delfunction(exarg_T *eap)
{
- ufunc_T *fp = NULL;
- char_u *p;
- char_u *name;
+ ufunc_T *fp = NULL;
+ char_u *p;
+ char_u *name;
funcdict_T fudi;
p = eap->arg;
name = trans_function_name(&p, eap->skip, 0, &fudi, NULL);
xfree(fudi.fd_newkey);
if (name == NULL) {
- if (fudi.fd_dict != NULL && !eap->skip)
+ if (fudi.fd_dict != NULL && !eap->skip) {
EMSG(_(e_funcref));
+ }
return;
}
if (!ends_excmd(*skipwhite(p))) {
@@ -2691,11 +2717,13 @@ void ex_delfunction(exarg_T *eap)
return;
}
eap->nextcmd = check_nextcmd(p);
- if (eap->nextcmd != NULL)
+ if (eap->nextcmd != NULL) {
*p = NUL;
+ }
- if (!eap->skip)
+ if (!eap->skip) {
fp = find_func(name);
+ }
xfree(name);
if (!eap->skip) {
@@ -2713,7 +2741,7 @@ void ex_delfunction(exarg_T *eap)
// the reference count, and 1 is the initial refcount.
if (fp->uf_refcount > 2) {
EMSG2(_("Cannot delete function %s: It is being used internally"),
- eap->arg);
+ eap->arg);
return;
}
@@ -2761,8 +2789,8 @@ void func_unref(char_u *name)
abort();
}
#else
- internal_error("func_unref()");
- abort();
+ internal_error("func_unref()");
+ abort();
#endif
}
func_ptr_unref(fp);
@@ -2843,7 +2871,7 @@ static int can_free_funccal(funccall_T *fc, int copyID)
*/
void ex_return(exarg_T *eap)
{
- char_u *arg = eap->arg;
+ char_u *arg = eap->arg;
typval_T rettv;
int returning = FALSE;
@@ -2852,8 +2880,9 @@ void ex_return(exarg_T *eap)
return;
}
- if (eap->skip)
+ if (eap->skip) {
++emsg_skip;
+ }
eap->nextcmd = NULL;
if ((*arg != NUL && *arg != '|' && *arg != '\n')
@@ -2883,25 +2912,26 @@ void ex_return(exarg_T *eap)
eap->nextcmd = check_nextcmd(arg);
}
- if (eap->skip)
+ if (eap->skip) {
--emsg_skip;
+ }
}
// TODO(ZyX-I): move to eval/ex_cmds
/*
- * ":1,25call func(arg1, arg2)" function call.
+ * ":1,25call func(arg1, arg2)" function call.
*/
void ex_call(exarg_T *eap)
{
- char_u *arg = eap->arg;
- char_u *startarg;
- char_u *name;
- char_u *tofree;
+ char_u *arg = eap->arg;
+ char_u *startarg;
+ char_u *name;
+ char_u *tofree;
int len;
typval_T rettv;
linenr_T lnum;
- int doesrange;
+ bool doesrange;
bool failed = false;
funcdict_T fudi;
partial_T *partial = NULL;
@@ -2947,7 +2977,7 @@ void ex_call(exarg_T *eap)
rettv.v_type = VAR_UNKNOWN; // tv_clear() uses this.
if (*startarg != '(') {
- EMSG2(_("E107: Missing parentheses: %s"), eap->arg);
+ EMSG2(_(e_missingparen), eap->arg);
goto end;
}
@@ -2965,15 +2995,22 @@ void ex_call(exarg_T *eap)
curwin->w_cursor.coladd = 0;
}
arg = startarg;
- if (get_func_tv(name, -1, &rettv, &arg,
- eap->line1, eap->line2, &doesrange,
- true, partial, fudi.fd_dict) == FAIL) {
+
+ funcexe_T funcexe = FUNCEXE_INIT;
+ funcexe.firstline = eap->line1;
+ funcexe.lastline = eap->line2;
+ funcexe.doesrange = &doesrange;
+ funcexe.evaluate = true;
+ funcexe.partial = partial;
+ funcexe.selfdict = fudi.fd_dict;
+ if (get_func_tv(name, -1, &rettv, &arg, &funcexe) == FAIL) {
failed = true;
break;
}
// Handle a function returning a Funcref, Dictionary or List.
- if (handle_subscript((const char **)&arg, &rettv, true, true)
+ if (handle_subscript((const char **)&arg, &rettv, true, true,
+ (const char_u *)name, (const char_u **)&name)
== FAIL) {
failed = true;
break;
@@ -3029,22 +3066,22 @@ int do_return(exarg_T *eap, int reanimate, int is_cmd, void *rettv)
current_funccal->returned = false;
}
- /*
- * Cleanup (and inactivate) conditionals, but stop when a try conditional
- * not in its finally clause (which then is to be executed next) is found.
- * In this case, make the ":return" pending for execution at the ":endtry".
- * Otherwise, return normally.
- */
- idx = cleanup_conditionals(eap->cstack, 0, TRUE);
+ //
+ // Cleanup (and deactivate) conditionals, but stop when a try conditional
+ // not in its finally clause (which then is to be executed next) is found.
+ // In this case, make the ":return" pending for execution at the ":endtry".
+ // Otherwise, return normally.
+ //
+ idx = cleanup_conditionals(eap->cstack, 0, true);
if (idx >= 0) {
cstack->cs_pending[idx] = CSTP_RETURN;
- if (!is_cmd && !reanimate)
+ if (!is_cmd && !reanimate) {
/* A pending return again gets pending. "rettv" points to an
* allocated variable with the rettv of the original ":return"'s
* argument if present or is NULL else. */
cstack->cs_rettv[idx] = rettv;
- else {
+ } else {
/* When undoing a return in order to make it pending, get the stored
* return rettv. */
if (reanimate) {
@@ -3056,8 +3093,9 @@ int do_return(exarg_T *eap, int reanimate, int is_cmd, void *rettv)
// Store the value of the pending return.
cstack->cs_rettv[idx] = xcalloc(1, sizeof(typval_T));
*(typval_T *)cstack->cs_rettv[idx] = *(typval_T *)rettv;
- } else
+ } else {
cstack->cs_rettv[idx] = NULL;
+ }
if (reanimate) {
/* The pending return value could be overwritten by a ":return"
@@ -3077,8 +3115,9 @@ int do_return(exarg_T *eap, int reanimate, int is_cmd, void *rettv)
if (!reanimate && rettv != NULL) {
tv_clear(current_funccal->rettv);
*current_funccal->rettv = *(typval_T *)rettv;
- if (!is_cmd)
+ if (!is_cmd) {
xfree(rettv);
+ }
}
}
@@ -3095,7 +3134,7 @@ char_u *get_return_cmd(void *rettv)
char_u *tofree = NULL;
if (rettv != NULL) {
- tofree = s = (char_u *) encode_tv2echo((typval_T *) rettv, NULL);
+ tofree = s = (char_u *)encode_tv2echo((typval_T *)rettv, NULL);
}
if (s == NULL) {
s = (char_u *)"";
@@ -3103,8 +3142,9 @@ char_u *get_return_cmd(void *rettv)
STRCPY(IObuff, ":return ");
STRLCPY(IObuff + 8, s, IOSIZE - 8);
- if (STRLEN(s) + 8 >= IOSIZE)
+ if (STRLEN(s) + 8 >= IOSIZE) {
STRCPY(IObuff + IOSIZE - 4, "...");
+ }
xfree(tofree);
return vim_strsave(IObuff);
}
@@ -3116,19 +3156,20 @@ char_u *get_return_cmd(void *rettv)
*/
char_u *get_func_line(int c, void *cookie, int indent, bool do_concat)
{
- funccall_T *fcp = (funccall_T *)cookie;
- ufunc_T *fp = fcp->func;
- char_u *retval;
- garray_T *gap; // growarray with function lines
+ funccall_T *fcp = (funccall_T *)cookie;
+ ufunc_T *fp = fcp->func;
+ char_u *retval;
+ garray_T *gap; // growarray with function lines
// If breakpoints have been added/deleted need to check for it.
if (fcp->dbg_tick != debug_tick) {
fcp->breakpoint = dbg_find_breakpoint(FALSE, fp->uf_name,
- sourcing_lnum);
+ sourcing_lnum);
fcp->dbg_tick = debug_tick;
}
- if (do_profiling == PROF_YES)
+ if (do_profiling == PROF_YES) {
func_line_end(cookie);
+ }
gap = &fp->uf_lines;
if (((fp->uf_flags & FC_ABORT) && did_emsg && !aborted_in_try())
@@ -3145,8 +3186,9 @@ char_u *get_func_line(int c, void *cookie, int indent, bool do_concat)
} else {
retval = vim_strsave(((char_u **)(gap->ga_data))[fcp->linenr++]);
sourcing_lnum = fcp->linenr;
- if (do_profiling == PROF_YES)
+ if (do_profiling == PROF_YES) {
func_line_start(cookie);
+ }
}
}
@@ -3168,7 +3210,7 @@ char_u *get_func_line(int c, void *cookie, int indent, bool do_concat)
*/
int func_has_ended(void *cookie)
{
- funccall_T *fcp = (funccall_T *)cookie;
+ funccall_T *fcp = (funccall_T *)cookie;
/* Ignore the "abort" flag if the abortion behavior has been changed due to
* an error inside a try conditional. */
@@ -3424,8 +3466,7 @@ hashitem_T *find_hi_in_scoped_ht(const char *name, hashtab_T **pht)
}
/// Search variable in parent scope.
-dictitem_T *find_var_in_scoped_ht(const char *name, const size_t namelen,
- int no_autoload)
+dictitem_T *find_var_in_scoped_ht(const char *name, const size_t namelen, int no_autoload)
{
if (current_funccal == NULL || current_funccal->func->uf_scoped == NULL) {
return NULL;
@@ -3459,54 +3500,54 @@ dictitem_T *find_var_in_scoped_ht(const char *name, const size_t namelen,
/// Set "copyID + 1" in previous_funccal and callers.
bool set_ref_in_previous_funccal(int copyID)
{
- bool abort = false;
-
- for (funccall_T *fc = previous_funccal; !abort && fc != NULL;
+ for (funccall_T *fc = previous_funccal; fc != NULL;
fc = fc->caller) {
fc->fc_copyID = copyID + 1;
- abort = abort
- || set_ref_in_ht(&fc->l_vars.dv_hashtab, copyID + 1, NULL)
- || set_ref_in_ht(&fc->l_avars.dv_hashtab, copyID + 1, NULL)
- || set_ref_in_list(&fc->l_varlist, copyID + 1, NULL);
+ if (set_ref_in_ht(&fc->l_vars.dv_hashtab, copyID + 1, NULL)
+ || set_ref_in_ht(&fc->l_avars.dv_hashtab, copyID + 1, NULL)
+ || set_ref_in_list(&fc->l_varlist, copyID + 1, NULL)) {
+ return true;
+ }
}
- return abort;
+ return false;
}
static bool set_ref_in_funccal(funccall_T *fc, int copyID)
{
- bool abort = false;
-
if (fc->fc_copyID != copyID) {
fc->fc_copyID = copyID;
- abort = abort
- || set_ref_in_ht(&fc->l_vars.dv_hashtab, copyID, NULL)
- || set_ref_in_ht(&fc->l_avars.dv_hashtab, copyID, NULL)
- || set_ref_in_list(&fc->l_varlist, copyID, NULL)
- || set_ref_in_func(NULL, fc->func, copyID);
+ if (set_ref_in_ht(&fc->l_vars.dv_hashtab, copyID, NULL)
+ || set_ref_in_ht(&fc->l_avars.dv_hashtab, copyID, NULL)
+ || set_ref_in_list(&fc->l_varlist, copyID, NULL)
+ || set_ref_in_func(NULL, fc->func, copyID)) {
+ return true;
+ }
}
- return abort;
+ return false;
}
/// Set "copyID" in all local vars and arguments in the call stack.
bool set_ref_in_call_stack(int copyID)
{
- bool abort = false;
-
- for (funccall_T *fc = current_funccal; !abort && fc != NULL;
+ for (funccall_T *fc = current_funccal; fc != NULL;
fc = fc->caller) {
- abort = abort || set_ref_in_funccal(fc, copyID);
+ if (set_ref_in_funccal(fc, copyID)) {
+ return true;
+ }
}
// Also go through the funccal_stack.
- for (funccal_entry_T *entry = funccal_stack; !abort && entry != NULL;
+ for (funccal_entry_T *entry = funccal_stack; entry != NULL;
entry = entry->next) {
- for (funccall_T *fc = entry->top_funccal; !abort && fc != NULL;
+ for (funccall_T *fc = entry->top_funccal; fc != NULL;
fc = fc->caller) {
- abort = abort || set_ref_in_funccal(fc, copyID);
+ if (set_ref_in_funccal(fc, copyID)) {
+ return true;
+ }
}
}
- return abort;
+ return false;
}
/// Set "copyID" in all functions available by name.
@@ -3514,7 +3555,6 @@ bool set_ref_in_functions(int copyID)
{
int todo;
hashitem_T *hi = NULL;
- bool abort = false;
ufunc_T *fp;
todo = (int)func_hashtab.ht_used;
@@ -3522,24 +3562,25 @@ bool set_ref_in_functions(int copyID)
if (!HASHITEM_EMPTY(hi)) {
todo--;
fp = HI2UF(hi);
- if (!func_name_refcount(fp->uf_name)) {
- abort = abort || set_ref_in_func(NULL, fp, copyID);
+ if (!func_name_refcount(fp->uf_name)
+ && set_ref_in_func(NULL, fp, copyID)) {
+ return true;
}
}
}
- return abort;
+ return false;
}
/// Set "copyID" in all function arguments.
bool set_ref_in_func_args(int copyID)
{
- bool abort = false;
-
for (int i = 0; i < funcargs.ga_len; i++) {
- abort = abort || set_ref_in_item(((typval_T **)funcargs.ga_data)[i],
- copyID, NULL, NULL);
+ if (set_ref_in_item(((typval_T **)funcargs.ga_data)[i],
+ copyID, NULL, NULL)) {
+ return true;
+ }
}
- return abort;
+ return false;
}
/// Mark all lists and dicts referenced through function "name" with "copyID".