aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/eval
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/eval')
-rw-r--r--src/nvim/eval/funcs.c44
-rw-r--r--src/nvim/eval/funcs.h1
-rw-r--r--src/nvim/eval/userfunc.c24
-rw-r--r--src/nvim/eval/userfunc.h2
4 files changed, 57 insertions, 14 deletions
diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c
index 363640adc5..787d5aaf78 100644
--- a/src/nvim/eval/funcs.c
+++ b/src/nvim/eval/funcs.c
@@ -175,6 +175,50 @@ const VimLFuncDef *find_internal_func(const char *const name)
return find_internal_func_gperf(name, len);
}
+int call_internal_func(const char_u *const fname, const int argcount,
+ typval_T *const argvars, typval_T *const rettv)
+ FUNC_ATTR_NONNULL_ALL
+{
+ const VimLFuncDef *const fdef = find_internal_func((const char *)fname);
+ if (fdef == NULL) {
+ return ERROR_UNKNOWN;
+ } else if (argcount < fdef->min_argc) {
+ return ERROR_TOOFEW;
+ } else if (argcount > fdef->max_argc) {
+ return ERROR_TOOMANY;
+ }
+ argvars[argcount].v_type = VAR_UNKNOWN;
+ fdef->func(argvars, rettv, fdef->data);
+ return ERROR_NONE;
+}
+
+/// Invoke a method for base->method().
+int call_internal_method(const char_u *const fname, const int argcount,
+ typval_T *const argvars, typval_T *const rettv,
+ typval_T *const basetv)
+ FUNC_ATTR_NONNULL_ALL
+{
+ const VimLFuncDef *const fdef = find_internal_func((const char *)fname);
+ if (fdef == NULL || fdef->base_arg == 0) {
+ return ERROR_UNKNOWN;
+ } else if (argcount + 1 < fdef->min_argc) {
+ return ERROR_TOOFEW;
+ } else if (argcount + 1 > fdef->max_argc) {
+ return ERROR_TOOMANY;
+ }
+
+ typval_T argv[MAX_FUNC_ARGS + 1];
+ const ptrdiff_t base_index = fdef->base_arg - 1;
+ memcpy(argv, argvars, base_index * sizeof(typval_T));
+ argv[base_index] = *basetv;
+ memcpy(argv + base_index + 1, argvars + base_index,
+ (argcount - base_index) * sizeof(typval_T));
+ argv[argcount + 1].v_type = VAR_UNKNOWN;
+
+ fdef->func(argv, rettv, fdef->data);
+ return ERROR_NONE;
+}
+
/*
* Return TRUE for a non-zero Number and a non-empty String.
*/
diff --git a/src/nvim/eval/funcs.h b/src/nvim/eval/funcs.h
index a343290734..3ad0b8282a 100644
--- a/src/nvim/eval/funcs.h
+++ b/src/nvim/eval/funcs.h
@@ -14,6 +14,7 @@ typedef struct fst {
char *name; ///< Name of the function.
uint8_t min_argc; ///< Minimal number of arguments.
uint8_t max_argc; ///< Maximal number of arguments.
+ uint8_t base_arg; ///< Method base arg # (1-indexed), or 0 if not a method.
VimLFunc func; ///< Function implementation.
FunPtr data; ///< Userdata for function implementation.
} VimLFuncDef;
diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c
index 516f7a1d53..ec43987b07 100644
--- a/src/nvim/eval/userfunc.c
+++ b/src/nvim/eval/userfunc.c
@@ -1514,7 +1514,10 @@ call_func(
}
} else if (fp != NULL || !builtin_function((const char *)rfname, -1)) {
// User defined function.
- if (fp == NULL) {
+ if (funcexe->basetv != NULL) {
+ // TODO(seandewar): support User function: base->Method()
+ fp = NULL;
+ } else if (fp == NULL) {
fp = find_func(rfname);
}
@@ -1560,20 +1563,13 @@ call_func(
error = ERROR_NONE;
}
}
+ } else if (funcexe->basetv != NULL) {
+ // Find the method name in the table, call its implementation.
+ 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
@@ -2937,7 +2933,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;
}
diff --git a/src/nvim/eval/userfunc.h b/src/nvim/eval/userfunc.h
index 9af35e0411..513473449a 100644
--- a/src/nvim/eval/userfunc.h
+++ b/src/nvim/eval/userfunc.h
@@ -44,6 +44,7 @@ typedef struct {
bool evaluate; ///< actually evaluate expressions
partial_T *partial; ///< for extra arguments
dict_T *selfdict; ///< Dictionary for "self"
+ typval_T *basetv; ///< base for base->method()
} funcexe_T;
#define FUNCEXE_INIT (funcexe_T) { \
@@ -54,6 +55,7 @@ typedef struct {
.evaluate = false, \
.partial = NULL, \
.selfdict = NULL, \
+ .basetv = NULL, \
}
#define FUNCARG(fp, j) ((char_u **)(fp->uf_args.ga_data))[j]