aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/nvim/eval/funcs.c25
-rw-r--r--src/nvim/eval/userfunc.c31
-rw-r--r--src/nvim/globals.h1
3 files changed, 53 insertions, 4 deletions
diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c
index f53b283c79..b064379210 100644
--- a/src/nvim/eval/funcs.c
+++ b/src/nvim/eval/funcs.c
@@ -228,6 +228,31 @@ const EvalFuncDef *find_internal_func(const char *const name)
return index >= 0 ? &functions[index] : NULL;
}
+/// Check the argument count to use for internal function "fdef".
+/// @return -1 for failure, 0 if no method base accepted, 1 if method base is
+/// first argument, 2 if method base is second argument, etc.
+int check_internal_func(const EvalFuncDef *const fdef, const int argcount)
+ FUNC_ATTR_NONNULL_ALL
+{
+ int res;
+
+ if (argcount < fdef->min_argc) {
+ res = FCERR_TOOFEW;
+ } else if (argcount > fdef->max_argc) {
+ res = FCERR_TOOMANY;
+ } else {
+ return fdef->base_arg;
+ }
+
+ const char *const name = fdef->name;
+ if (res == FCERR_TOOMANY) {
+ semsg(_(e_toomanyarg), name);
+ } else {
+ semsg(_(e_toofewarg), name);
+ }
+ return -1;
+}
+
int call_internal_func(const char *const fname, const int argcount, typval_T *const argvars,
typval_T *const rettv)
FUNC_ATTR_NONNULL_ALL
diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c
index 32f9f9182c..65918ba2bf 100644
--- a/src/nvim/eval/userfunc.c
+++ b/src/nvim/eval/userfunc.c
@@ -72,7 +72,7 @@ static funccall_T *current_funccal = NULL;
// item in it is still being used.
static funccall_T *previous_funccal = NULL;
-static const char *e_unknownfunc = N_("E117: Unknown function: %s");
+static const char *e_unknown_function_str = N_("E117: Unknown function: %s");
static const char *e_funcexts = N_("E122: Function %s already exists, add ! to replace it");
static const char *e_funcdict = N_("E717: Dictionary entry already exists");
static const char *e_funcref = N_("E718: Funcref required");
@@ -1523,14 +1523,14 @@ varnumber_T callback_call_retnr(Callback *callback, int argcount, typval_T *argv
/// Give an error message for the result of a function.
/// Nothing if "error" is FCERR_NONE.
static void user_func_error(int error, const char *name, funcexe_T *funcexe)
- FUNC_ATTR_NONNULL_ALL
+ FUNC_ATTR_NONNULL_ARG(2)
{
switch (error) {
case FCERR_UNKNOWN:
if (funcexe->fe_found_var) {
semsg(_(e_not_callable_type_str), name);
} else {
- emsg_funcname(e_unknownfunc, name);
+ emsg_funcname(e_unknown_function_str, name);
}
break;
case FCERR_NOTMETHOD:
@@ -1543,7 +1543,7 @@ static void user_func_error(int error, const char *name, funcexe_T *funcexe)
emsg_funcname(_(e_toomanyarg), name);
break;
case FCERR_TOOFEW:
- emsg_funcname(N_("E119: Not enough arguments for function: %s"), name);
+ emsg_funcname(_(e_toofewarg), name);
break;
case FCERR_SCRIPT:
emsg_funcname(N_("E120: Using <SID> not in a script context: %s"), name);
@@ -3172,6 +3172,29 @@ static int ex_defer_inner(char *name, char **arg, const partial_T *const partial
}
int r = get_func_arguments(arg, evalarg, false, argvars + partial_argc, &argcount);
argcount += partial_argc;
+
+ if (r == OK) {
+ if (builtin_function(name, -1)) {
+ const EvalFuncDef *const fdef = find_internal_func(name);
+ if (fdef == NULL) {
+ emsg_funcname(e_unknown_function_str, name);
+ r = FAIL;
+ } else if (check_internal_func(fdef, argcount) == -1) {
+ r = FAIL;
+ }
+ } else {
+ ufunc_T *ufunc = find_func(name);
+ // we tolerate an unknown function here, it might be defined later
+ if (ufunc != NULL) {
+ int error = check_user_func_argcount(ufunc, argcount);
+ if (error != FCERR_UNKNOWN) {
+ user_func_error(error, name, NULL);
+ r = FAIL;
+ }
+ }
+ }
+ }
+
if (r == FAIL) {
while (--argcount >= 0) {
tv_clear(&argvars[argcount]);
diff --git a/src/nvim/globals.h b/src/nvim/globals.h
index 66df1f8920..0c7f55714c 100644
--- a/src/nvim/globals.h
+++ b/src/nvim/globals.h
@@ -953,6 +953,7 @@ EXTERN const char e_dictreq[] INIT(= N_("E715: Dictionary required"));
EXTERN const char e_blobidx[] INIT(= N_("E979: Blob index out of range: %" PRId64));
EXTERN const char e_invalblob[] INIT(= N_("E978: Invalid operation for Blob"));
EXTERN const char e_toomanyarg[] INIT(= N_("E118: Too many arguments for function: %s"));
+EXTERN const char e_toofewarg[] INIT(= N_("E119: Not enough arguments for function: %s"));
EXTERN const char e_dictkey[] INIT(= N_("E716: Key not present in Dictionary: \"%s\""));
EXTERN const char e_listreq[] INIT(= N_("E714: List required"));
EXTERN const char e_listblobreq[] INIT(= N_("E897: List or Blob required"));