aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/eval
diff options
context:
space:
mode:
authorSean Dewar <seandewar@users.noreply.github.com>2021-05-21 15:12:35 +0100
committerSean Dewar <seandewar@users.noreply.github.com>2021-08-12 22:31:18 +0100
commit4042ae5a2bc4bbca608ebb196a3d54a78d6c100c (patch)
tree6da940b00ff0f62ef3a2ebdeb730726e0f69755b /src/nvim/eval
parent60dd76c7e29e75dee641f93483eb6e5c2afb28e4 (diff)
downloadrneovim-4042ae5a2bc4bbca608ebb196a3d54a78d6c100c.tar.gz
rneovim-4042ae5a2bc4bbca608ebb196a3d54a78d6c100c.tar.bz2
rneovim-4042ae5a2bc4bbca608ebb196a3d54a78d6c100c.zip
vim-patch:8.1.1800: function call functions have too many arguments
Problem: Function call functions have too many arguments. Solution: Pass values in a funcexe_T struct. https://github.com/vim/vim/commit/c6538bcc1cdd1fb83732f22fdc69bd9bb66f968a Use FUNCEXE_INIT to initialize funcexe_T instances. call_callback() and other Vim listener related stuff is N/A.
Diffstat (limited to 'src/nvim/eval')
-rw-r--r--src/nvim/eval/funcs.c10
-rw-r--r--src/nvim/eval/userfunc.c80
-rw-r--r--src/nvim/eval/userfunc.h23
3 files changed, 66 insertions, 47 deletions
diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c
index 4e409cca50..363640adc5 100644
--- a/src/nvim/eval/funcs.c
+++ b/src/nvim/eval/funcs.c
@@ -9420,7 +9420,6 @@ static int item_compare2(const void *s1, const void *s2, bool keep_zero)
int res;
typval_T rettv;
typval_T argv[3];
- int dummy;
const char *func_name;
partial_T *partial = sortinfo->item_compare_partial;
@@ -9444,10 +9443,11 @@ static int item_compare2(const void *s1, const void *s2, bool keep_zero)
tv_copy(TV_LIST_ITEM_TV(si2->item), &argv[1]);
rettv.v_type = VAR_UNKNOWN; // tv_clear() uses this
- res = call_func((const char_u *)func_name,
- -1,
- &rettv, 2, argv, NULL, 0L, 0L, &dummy, true,
- partial, sortinfo->item_compare_selfdict);
+ funcexe_T funcexe = FUNCEXE_INIT;
+ funcexe.evaluate = true;
+ funcexe.partial = partial;
+ funcexe.selfdict = sortinfo->item_compare_selfdict;
+ res = call_func((const char_u *)func_name, -1, &rettv, 2, argv, &funcexe);
tv_clear(&argv[0]);
tv_clear(&argv[1]);
diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c
index deddec413b..516f7a1d53 100644
--- a/src/nvim/eval/userfunc.c
+++ b/src/nvim/eval/userfunc.c
@@ -414,12 +414,7 @@ get_func_tv(
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"
+ funcexe_T *funcexe // various values
)
{
char_u *argp;
@@ -431,12 +426,13 @@ get_func_tv(
* 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;
}
@@ -463,9 +459,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()) {
@@ -1367,7 +1361,6 @@ int func_call(char_u *name, typval_T *args, partial_T *partial,
{
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 +1373,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.
@@ -1425,10 +1422,6 @@ static void user_func_error(int error, const char_u *name)
/// 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()).
@@ -1440,15 +1433,9 @@ call_func(
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"
+ funcexe_T *funcexe // more arguments
)
- FUNC_ATTR_NONNULL_ARG(1, 3, 5, 9)
+ FUNC_ATTR_NONNULL_ARG(1, 3, 5, 6)
{
int ret = FAIL;
int error = ERROR_NONE;
@@ -1459,9 +1446,10 @@ call_func(
char_u *name = NULL;
int argcount = argcount_in;
typval_T *argvars = argvars_in;
- dict_T *selfdict = selfdict_in;
+ dict_T *selfdict = funcexe->selfdict;
typval_T argv[MAX_FUNC_ARGS + 1]; // used when "partial" is not NULL
int argv_clear = 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 +1468,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 +1495,7 @@ call_func(
}
}
- if (error == ERROR_NONE && evaluate) {
+ if (error == ERROR_NONE && funcexe->evaluate) {
char_u *rfname = fname;
// Ignore "g:" before a function name.
@@ -1549,13 +1538,13 @@ 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;
+ 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,7 +1554,8 @@ 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;
}
@@ -2901,7 +2891,7 @@ void ex_call(exarg_T *eap)
int len;
typval_T rettv;
linenr_T lnum;
- int doesrange;
+ bool doesrange;
bool failed = false;
funcdict_T fudi;
partial_T *partial = NULL;
@@ -2965,9 +2955,15 @@ 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;
}
diff --git a/src/nvim/eval/userfunc.h b/src/nvim/eval/userfunc.h
index e8ad0bf1da..9af35e0411 100644
--- a/src/nvim/eval/userfunc.h
+++ b/src/nvim/eval/userfunc.h
@@ -30,9 +30,32 @@ typedef enum {
ERROR_DELETED,
} FnameTransError;
+/// Used in funcexe_T. Returns the new argcount.
typedef int (*ArgvFunc)(int current_argcount, typval_T *argv, int argskip,
int called_func_argcount);
+/// Structure passed between functions dealing with function call execution.
+typedef struct {
+ ArgvFunc argv_func; ///< when not NULL, can be used to fill in arguments only
+ ///< when the invoked function uses them
+ linenr_T firstline; ///< first line of range
+ linenr_T lastline; ///< last line of range
+ bool *doesrange; ///< [out] if not NULL: function handled range
+ bool evaluate; ///< actually evaluate expressions
+ partial_T *partial; ///< for extra arguments
+ dict_T *selfdict; ///< Dictionary for "self"
+} funcexe_T;
+
+#define FUNCEXE_INIT (funcexe_T) { \
+ .argv_func = NULL, \
+ .firstline = 0, \
+ .lastline = 0, \
+ .doesrange = NULL, \
+ .evaluate = false, \
+ .partial = NULL, \
+ .selfdict = NULL, \
+}
+
#define FUNCARG(fp, j) ((char_u **)(fp->uf_args.ga_data))[j]
#define FUNCLINE(fp, j) ((char_u **)(fp->uf_lines.ga_data))[j]