aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/eval
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/eval')
-rw-r--r--src/nvim/eval/decode.c2
-rw-r--r--src/nvim/eval/funcs.c186
-rw-r--r--src/nvim/eval/userfunc.c214
3 files changed, 252 insertions, 150 deletions
diff --git a/src/nvim/eval/decode.c b/src/nvim/eval/decode.c
index daba304f00..638fef331a 100644
--- a/src/nvim/eval/decode.c
+++ b/src/nvim/eval/decode.c
@@ -586,7 +586,7 @@ parse_json_number_check:
if (p == ints) {
emsgf(_("E474: Missing number after minus sign: %.*s"), LENP(s, e));
goto parse_json_number_fail;
- } else if (p == fracs || exps_s == fracs + 1) {
+ } else if (p == fracs || (fracs != NULL && exps_s == fracs + 1)) {
emsgf(_("E474: Missing number after decimal dot: %.*s"), LENP(s, e));
goto parse_json_number_fail;
} else if (p == exps) {
diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c
index 1a80d4d4bd..83ef9c8762 100644
--- a/src/nvim/eval/funcs.c
+++ b/src/nvim/eval/funcs.c
@@ -32,6 +32,7 @@
#include "nvim/indent.h"
#include "nvim/indent_c.h"
#include "nvim/lua/executor.h"
+#include "nvim/macros.h"
#include "nvim/mark.h"
#include "nvim/math.h"
#include "nvim/memline.h"
@@ -86,8 +87,10 @@ KHASH_MAP_INIT_STR(functions, VimLFuncDef)
#endif
PRAGMA_DIAG_PUSH_IGNORE_MISSING_PROTOTYPES
+PRAGMA_DIAG_PUSH_IGNORE_IMPLICIT_FALLTHROUGH
#include "funcs.generated.h"
PRAGMA_DIAG_POP
+PRAGMA_DIAG_POP
#endif
@@ -2068,6 +2071,12 @@ static void f_expand(typval_T *argvars, typval_T *rettv, FunPtr fptr)
expand_T xpc;
bool error = false;
char_u *result;
+#ifdef BACKSLASH_IN_FILENAME
+ char_u *p_csl_save = p_csl;
+
+ // avoid using 'completeslash' here
+ p_csl = empty_option;
+#endif
rettv->v_type = VAR_STRING;
if (argvars[1].v_type != VAR_UNKNOWN
@@ -2120,6 +2129,9 @@ static void f_expand(typval_T *argvars, typval_T *rettv, FunPtr fptr)
rettv->vval.v_string = NULL;
}
}
+#ifdef BACKSLASH_IN_FILENAME
+ p_csl = p_csl_save;
+#endif
}
@@ -2407,9 +2419,9 @@ static void f_float2nr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
float_T f;
if (tv_get_float_chk(argvars, &f)) {
- if (f <= -VARNUMBER_MAX + DBL_EPSILON) {
+ if (f <= (float_T)-VARNUMBER_MAX + DBL_EPSILON) {
rettv->vval.v_number = -VARNUMBER_MAX;
- } else if (f >= VARNUMBER_MAX - DBL_EPSILON) {
+ } else if (f >= (float_T)VARNUMBER_MAX - DBL_EPSILON) {
rettv->vval.v_number = VARNUMBER_MAX;
} else {
rettv->vval.v_number = (varnumber_T)f;
@@ -2581,8 +2593,6 @@ static void f_foldtextresult(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
char_u *text;
char_u buf[FOLD_TEXT_LEN];
- foldinfo_T foldinfo;
- int fold_count;
static bool entered = false;
rettv->v_type = VAR_STRING;
@@ -2596,9 +2606,10 @@ static void f_foldtextresult(typval_T *argvars, typval_T *rettv, FunPtr fptr)
if (lnum < 0) {
lnum = 0;
}
- fold_count = foldedCount(curwin, lnum, &foldinfo);
- if (fold_count > 0) {
- text = get_foldtext(curwin, lnum, lnum + fold_count - 1, &foldinfo, buf);
+
+ foldinfo_T info = fold_info(curwin, lnum);
+ if (info.fi_lines > 0) {
+ text = get_foldtext(curwin, lnum, lnum + info.fi_lines - 1, info, buf);
if (text == buf) {
text = vim_strsave(text);
}
@@ -4005,7 +4016,7 @@ static void f_glob(typval_T *argvars, typval_T *rettv, FunPtr fptr)
/// "globpath()" function
static void f_globpath(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- int flags = 0; // Flags for globpath.
+ int flags = WILD_IGNORE_COMPLETESLASH; // Flags for globpath.
bool error = false;
// Return a string, or a list if the optional third argument is non-zero.
@@ -4717,6 +4728,14 @@ static void f_insert(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
}
+// "interrupt()" function
+static void f_interrupt(typval_T *argvars FUNC_ATTR_UNUSED,
+ typval_T *rettv FUNC_ATTR_UNUSED,
+ FunPtr fptr FUNC_ATTR_UNUSED)
+{
+ got_int = true;
+}
+
/*
* "invert(expr)" function
*/
@@ -5471,7 +5490,7 @@ static void f_luaeval(typval_T *argvars, typval_T *rettv, FunPtr fptr)
return;
}
- executor_eval_lua(cstr_as_string((char *)str), &argvars[1], rettv);
+ nlua_typval_eval(cstr_as_string((char *)str), &argvars[1], rettv);
}
/*
@@ -6363,6 +6382,20 @@ static void f_pyxeval(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
}
+///
+/// "perleval()" function
+///
+static void f_perleval(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+{
+ script_host_eval("perl", argvars, rettv);
+}
+
+// "rubyeval()" function
+static void f_rubyeval(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+{
+ script_host_eval("ruby", argvars, rettv);
+}
+
/*
* "range()" function
*/
@@ -6918,7 +6951,7 @@ static void f_resolve(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
ptrdiff_t len = (ptrdiff_t)strlen(p);
- if (len > 0 && after_pathsep(p, p + len)) {
+ if (len > 1 && after_pathsep(p, p + len)) {
has_trailing_pathsep = true;
p[len - 1] = NUL; // The trailing slash breaks readlink().
}
@@ -7650,7 +7683,7 @@ static int searchpair_cmn(typval_T *argvars, pos_T *match_pos)
}
retval = do_searchpair(
- (char_u *)spat, (char_u *)mpat, (char_u *)epat, dir, skip,
+ spat, mpat, epat, dir, skip,
flags, match_pos, lnum_stop, time_limit);
theend:
@@ -7694,9 +7727,9 @@ static void f_searchpairpos(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
long
do_searchpair(
- char_u *spat, // start pattern
- char_u *mpat, // middle pattern
- char_u *epat, // end pattern
+ const char *spat, // start pattern
+ const char *mpat, // middle pattern
+ const char *epat, // end pattern
int dir, // BACKWARD or FORWARD
const typval_T *skip, // skip expression
int flags, // SP_SETPCMARK and other SP_ values
@@ -7704,6 +7737,7 @@ do_searchpair(
linenr_T lnum_stop, // stop at this line if not zero
long time_limit // stop after this many msec
)
+ FUNC_ATTR_NONNULL_ARG(1, 2, 3)
{
char_u *save_cpo;
char_u *pat, *pat2 = NULL, *pat3 = NULL;
@@ -7718,8 +7752,6 @@ do_searchpair(
bool use_skip = false;
int options = SEARCH_KEEP;
proftime_T tm;
- size_t pat2_len;
- size_t pat3_len;
// Make 'cpoptions' empty, the 'l' flag should not be used here.
save_cpo = p_cpo;
@@ -7730,9 +7762,9 @@ do_searchpair(
// Make two search patterns: start/end (pat2, for in nested pairs) and
// start/middle/end (pat3, for the top pair).
- pat2_len = STRLEN(spat) + STRLEN(epat) + 17;
+ const size_t pat2_len = strlen(spat) + strlen(epat) + 17;
pat2 = xmalloc(pat2_len);
- pat3_len = STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25;
+ const size_t pat3_len = strlen(spat) + strlen(mpat) + strlen(epat) + 25;
pat3 = xmalloc(pat3_len);
snprintf((char *)pat2, pat2_len, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
if (*mpat == NUL) {
@@ -8124,15 +8156,17 @@ static void f_setline(typval_T *argvars, typval_T *rettv, FunPtr fptr)
/// Create quickfix/location list from VimL values
///
/// Used by `setqflist()` and `setloclist()` functions. Accepts invalid
-/// list_arg, action_arg and what_arg arguments in which case errors out,
-/// including VAR_UNKNOWN parameters.
+/// args argument in which case errors out, including VAR_UNKNOWN parameters.
///
/// @param[in,out] wp Window to create location list for. May be NULL in
/// which case quickfix list will be created.
-/// @param[in] list_arg Quickfix list contents.
-/// @param[in] action_arg Action to perform: append to an existing list,
-/// replace its content or create a new one.
-/// @param[in] title_arg New list title. Defaults to caller function name.
+/// @param[in] args [list, action, what]
+/// @param[in] args[0] Quickfix list contents.
+/// @param[in] args[1] Optional. Action to perform:
+/// append to an existing list, replace its content,
+/// or create a new one.
+/// @param[in] args[2] Optional. Quickfix list properties or title.
+/// Defaults to caller function name.
/// @param[out] rettv Return value: 0 in case of success, -1 otherwise.
static void set_qf_ll_list(win_T *wp, typval_T *args, typval_T *rettv)
FUNC_ATTR_NONNULL_ARG(2, 3)
@@ -8142,7 +8176,7 @@ static void set_qf_ll_list(win_T *wp, typval_T *args, typval_T *rettv)
int action = ' ';
static int recursive = 0;
rettv->vval.v_number = -1;
- dict_T *d = NULL;
+ dict_T *what = NULL;
typval_T *list_arg = &args[0];
if (list_arg->v_type != VAR_LIST) {
@@ -8170,18 +8204,18 @@ static void set_qf_ll_list(win_T *wp, typval_T *args, typval_T *rettv)
return;
}
- typval_T *title_arg = &args[2];
- if (title_arg->v_type == VAR_UNKNOWN) {
+ typval_T *const what_arg = &args[2];
+ if (what_arg->v_type == VAR_UNKNOWN) {
// Option argument was not given.
goto skip_args;
- } else if (title_arg->v_type == VAR_STRING) {
- title = tv_get_string_chk(title_arg);
+ } else if (what_arg->v_type == VAR_STRING) {
+ title = tv_get_string_chk(what_arg);
if (!title) {
// Type error. Error already printed by tv_get_string_chk().
return;
}
- } else if (title_arg->v_type == VAR_DICT) {
- d = title_arg->vval.v_dict;
+ } else if (what_arg->v_type == VAR_DICT && what_arg->vval.v_dict != NULL) {
+ what = what_arg->vval.v_dict;
} else {
EMSG(_(e_dictreq));
return;
@@ -8194,7 +8228,7 @@ skip_args:
recursive++;
list_T *const l = list_arg->vval.v_list;
- if (set_errorlist(wp, l, action, (char_u *)title, d) == OK) {
+ if (set_errorlist(wp, l, action, (char_u *)title, what) == OK) {
rettv->vval.v_number = 0;
}
recursive--;
@@ -9156,7 +9190,7 @@ static int item_compare2(const void *s1, const void *s2, bool keep_zero)
rettv.v_type = VAR_UNKNOWN; // tv_clear() uses this
res = call_func((const char_u *)func_name,
- (int)STRLEN(func_name),
+ -1,
&rettv, 2, argv, NULL, 0L, 0L, &dummy, true,
partial, sortinfo->item_compare_selfdict);
tv_clear(&argv[0]);
@@ -9938,6 +9972,16 @@ static void f_strpart(typval_T *argvars, typval_T *rettv, FunPtr fptr)
len = slen - n;
}
+ if (argvars[2].v_type != VAR_UNKNOWN && argvars[3].v_type != VAR_UNKNOWN) {
+ int off;
+
+ // length in characters
+ for (off = n; off < (int)slen && len > 0; len--) {
+ off += utfc_ptr2len((char_u *)p + off);
+ }
+ len = off - n;
+ }
+
rettv->v_type = VAR_STRING;
rettv->vval.v_string = (char_u *)xmemdupz(p + n, (size_t)len);
}
@@ -10796,52 +10840,72 @@ static void f_trim(typval_T *argvars, typval_T *rettv, FunPtr fptr)
const char_u *prev;
const char_u *p;
int c1;
+ int dir = 0;
rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = NULL;
if (head == NULL) {
- rettv->vval.v_string = NULL;
return;
}
if (argvars[1].v_type == VAR_STRING) {
mask = (const char_u *)tv_get_string_buf_chk(&argvars[1], buf2);
+ if (argvars[2].v_type != VAR_UNKNOWN) {
+ bool error = false;
+ // leading or trailing characters to trim
+ dir = (int)tv_get_number_chk(&argvars[2], &error);
+ if (error) {
+ return;
+ }
+ if (dir < 0 || dir > 2) {
+ emsgf(_(e_invarg2), tv_get_string(&argvars[2]));
+ return;
+ }
+ }
}
- while (*head != NUL) {
- c1 = PTR2CHAR(head);
- if (mask == NULL) {
- if (c1 > ' ' && c1 != 0xa0) {
- break;
- }
- } else {
- for (p = mask; *p != NUL; MB_PTR_ADV(p)) {
- if (c1 == PTR2CHAR(p)) {
+ if (dir == 0 || dir == 1) {
+ // Trim leading characters
+ while (*head != NUL) {
+ c1 = PTR2CHAR(head);
+ if (mask == NULL) {
+ if (c1 > ' ' && c1 != 0xa0) {
+ break;
+ }
+ } else {
+ for (p = mask; *p != NUL; MB_PTR_ADV(p)) {
+ if (c1 == PTR2CHAR(p)) {
+ break;
+ }
+ }
+ if (*p == NUL) {
break;
}
}
- if (*p == NUL) {
- break;
- }
+ MB_PTR_ADV(head);
}
- MB_PTR_ADV(head);
}
- for (tail = head + STRLEN(head); tail > head; tail = prev) {
- prev = tail;
- MB_PTR_BACK(head, prev);
- c1 = PTR2CHAR(prev);
- if (mask == NULL) {
- if (c1 > ' ' && c1 != 0xa0) {
- break;
- }
- } else {
- for (p = mask; *p != NUL; MB_PTR_ADV(p)) {
- if (c1 == PTR2CHAR(p)) {
+ tail = head + STRLEN(head);
+ if (dir == 0 || dir == 2) {
+ // Trim trailing characters
+ for (; tail > head; tail = prev) {
+ prev = tail;
+ MB_PTR_BACK(head, prev);
+ c1 = PTR2CHAR(prev);
+ if (mask == NULL) {
+ if (c1 > ' ' && c1 != 0xa0) {
+ break;
+ }
+ } else {
+ for (p = mask; *p != NUL; MB_PTR_ADV(p)) {
+ if (c1 == PTR2CHAR(p)) {
+ break;
+ }
+ }
+ if (*p == NUL) {
break;
}
- }
- if (*p == NUL) {
- break;
}
}
}
diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c
index 229f0e8dde..dc94bc698d 100644
--- a/src/nvim/eval/userfunc.c
+++ b/src/nvim/eval/userfunc.c
@@ -32,7 +32,11 @@
#define FC_DELETED 0x10 // :delfunction used while uf_refcount > 0
#define FC_REMOVED 0x20 // function redefined while uf_refcount > 0
#define FC_SANDBOX 0x40 // function defined in the sandbox
-#define FC_CFUNC 0x80 // C function extension
+#define FC_DEAD 0x80 // function kept only for reference to dfunc
+#define FC_EXPORT 0x100 // "export def Func()"
+#define FC_NOARGS 0x200 // no a: variables in lambda
+#define FC_VIM9 0x400 // defined in vim9 script file
+#define FC_CFUNC 0x800 // C function extension
#ifdef INCLUDE_GENERATED_DECLARATIONS
#include "eval/userfunc.c.generated.h"
@@ -246,6 +250,10 @@ int get_lambda_tv(char_u **arg, typval_T *rettv, bool evaluate)
((char_u **)(newlines.ga_data))[newlines.ga_len++] = p;
STRCPY(p, "return ");
STRLCPY(p + 7, s, e - s + 1);
+ if (strstr((char *)p + 7, "a:") == NULL) {
+ // No a: variables are used for sure.
+ flags |= FC_NOARGS;
+ }
fp->uf_refcount = 1;
STRCPY(fp->uf_name, name);
@@ -367,7 +375,7 @@ void emsg_funcname(char *ermsg, const char_u *name)
int
get_func_tv(
const char_u *name, // name of the function
- int len, // length of "name"
+ 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
@@ -813,17 +821,12 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars,
current_funccal = fc;
fc->func = fp;
fc->rettv = rettv;
- rettv->vval.v_number = 0;
- fc->linenr = 0;
- fc->returned = FALSE;
fc->level = ex_nesting_level;
// Check if this function has a breakpoint.
fc->breakpoint = dbg_find_breakpoint(false, fp->uf_name, (linenr_T)0);
fc->dbg_tick = debug_tick;
// Set up fields for closure.
- fc->fc_refcount = 0;
- fc->fc_copyID = 0;
ga_init(&fc->fc_funcs, sizeof(ufunc_T *), 1);
func_ptr_ref(fp);
@@ -853,37 +856,42 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars,
++selfdict->dv_refcount;
}
- /*
- * Init a: variables.
- * Set a:0 to "argcount".
- * Set a:000 to a list with room for the "..." arguments.
- */
+ // Init a: variables, unless none found (in lambda).
+ // Set a:0 to "argcount".
+ // Set a:000 to a list with room for the "..." arguments.
init_var_dict(&fc->l_avars, &fc->l_avars_var, VAR_SCOPE);
- add_nr_var(&fc->l_avars, (dictitem_T *)&fc->fixvar[fixvar_idx++], "0",
- (varnumber_T)(argcount - fp->uf_args.ga_len));
+ if ((fp->uf_flags & FC_NOARGS) == 0) {
+ add_nr_var(&fc->l_avars, (dictitem_T *)&fc->fixvar[fixvar_idx++], "0",
+ (varnumber_T)(argcount - fp->uf_args.ga_len));
+ }
fc->l_avars.dv_lock = VAR_FIXED;
- // Use "name" to avoid a warning from some compiler that checks the
- // destination size.
- v = (dictitem_T *)&fc->fixvar[fixvar_idx++];
+ if ((fp->uf_flags & FC_NOARGS) == 0) {
+ // Use "name" to avoid a warning from some compiler that checks the
+ // destination size.
+ v = (dictitem_T *)&fc->fixvar[fixvar_idx++];
#ifndef __clang_analyzer__
- name = v->di_key;
- STRCPY(name, "000");
+ name = v->di_key;
+ STRCPY(name, "000");
#endif
- v->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX;
- tv_dict_add(&fc->l_avars, v);
- v->di_tv.v_type = VAR_LIST;
- v->di_tv.v_lock = VAR_FIXED;
- v->di_tv.vval.v_list = &fc->l_varlist;
+ v->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX;
+ tv_dict_add(&fc->l_avars, v);
+ v->di_tv.v_type = VAR_LIST;
+ v->di_tv.v_lock = VAR_FIXED;
+ v->di_tv.vval.v_list = &fc->l_varlist;
+ }
tv_list_init_static(&fc->l_varlist);
tv_list_set_lock(&fc->l_varlist, VAR_FIXED);
// Set a:firstline to "firstline" and a:lastline to "lastline".
// Set a:name to named arguments.
// Set a:N to the "..." arguments.
- add_nr_var(&fc->l_avars, (dictitem_T *)&fc->fixvar[fixvar_idx++],
- "firstline", (varnumber_T)firstline);
- add_nr_var(&fc->l_avars, (dictitem_T *)&fc->fixvar[fixvar_idx++],
- "lastline", (varnumber_T)lastline);
+ // Skipped when no a: variables used (in lambda).
+ if ((fp->uf_flags & FC_NOARGS) == 0) {
+ add_nr_var(&fc->l_avars, (dictitem_T *)&fc->fixvar[fixvar_idx++],
+ "firstline", (varnumber_T)firstline);
+ add_nr_var(&fc->l_avars, (dictitem_T *)&fc->fixvar[fixvar_idx++],
+ "lastline", (varnumber_T)lastline);
+ }
for (int i = 0; i < argcount; i++) {
bool addlocal = false;
@@ -895,6 +903,10 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars,
addlocal = true;
}
} else {
+ if ((fp->uf_flags & FC_NOARGS) != 0) {
+ // Bail out if no a: arguments used (in lambda).
+ break;
+ }
// "..." argument a:1, a:2, etc.
snprintf((char *)numbuf, sizeof(numbuf), "%d", ai + 1);
name = numbuf;
@@ -1034,9 +1046,19 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars,
save_did_emsg = did_emsg;
did_emsg = FALSE;
- // call do_cmdline() to execute the lines
- do_cmdline(NULL, get_func_line, (void *)fc,
- DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT);
+ if (islambda) {
+ char_u *p = *(char_u **)fp->uf_lines.ga_data + 7;
+
+ // A Lambda always has the command "return {expr}". It is much faster
+ // to evaluate {expr} directly.
+ ex_nesting_level++;
+ (void)eval1(&p, rettv, true);
+ ex_nesting_level--;
+ } else {
+ // call do_cmdline() to execute the lines
+ do_cmdline(NULL, get_func_line, (void *)fc,
+ DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT);
+ }
--RedrawingDisabled;
@@ -1291,7 +1313,7 @@ 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, (int)STRLEN(name), rettv, argc, argv, NULL,
+ r = call_func(name, -1, rettv, argc, argv, NULL,
curwin->w_cursor.lnum, curwin->w_cursor.lnum,
&dummy, true, partial, selfdict);
@@ -1304,6 +1326,36 @@ func_call_skip_call:
return r;
}
+// 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_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;
+ }
+}
+
/// Call a function with its resolved parameters
///
/// "argv_func", when not NULL, can be used to fill in arguments only when the
@@ -1316,7 +1368,7 @@ func_call_skip_call:
int
call_func(
const char_u *funcname, // name of the function
- int len, // length of "name"
+ 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"
@@ -1333,11 +1385,11 @@ call_func(
{
int ret = FAIL;
int error = ERROR_NONE;
- ufunc_T *fp;
+ ufunc_T *fp = NULL;
char_u fname_buf[FLEN_FIXED + 1];
char_u *tofree = NULL;
- char_u *fname;
- char_u *name;
+ char_u *fname = NULL;
+ char_u *name = NULL;
int argcount = argcount_in;
typval_T *argvars = argvars_in;
dict_T *selfdict = selfdict_in;
@@ -1348,11 +1400,18 @@ call_func(
// even when call_func() returns FAIL.
rettv->v_type = VAR_UNKNOWN;
- // Make a copy of the name, if it comes from a funcref variable it could
- // be changed or deleted in the called function.
- name = vim_strnsave(funcname, len);
-
- fname = fname_trans_sid(name, fname_buf, &tofree, &error);
+ if (len <= 0) {
+ len = (int)STRLEN(funcname);
+ }
+ if (partial != NULL) {
+ fp = partial->pt_func;
+ }
+ if (fp == NULL) {
+ // Make a copy of the name, if it comes from a funcref variable it could
+ // be changed or deleted in the called function.
+ name = vim_strnsave(funcname, len);
+ fname = fname_trans_sid(name, fname_buf, &tofree, &error);
+ }
*doesrange = false;
@@ -1384,7 +1443,7 @@ call_func(
char_u *rfname = fname;
// Ignore "g:" before a function name.
- if (fname[0] == 'g' && fname[1] == ':') {
+ if (fp == NULL && fname[0] == 'g' && fname[1] == ':') {
rfname = fname + 2;
}
@@ -1395,14 +1454,11 @@ call_func(
if (is_luafunc(partial)) {
if (len > 0) {
error = ERROR_NONE;
- executor_call_lua((const char *)funcname, len,
- argvars, argcount, rettv);
+ nlua_typval_call((const char *)funcname, len, argvars, argcount, rettv);
}
- } else if (!builtin_function((const char *)rfname, -1)) {
+ } else if (fp != NULL || !builtin_function((const char *)rfname, -1)) {
// User defined function.
- if (partial != NULL && partial->pt_func != NULL) {
- fp = partial->pt_func;
- } else {
+ if (fp == NULL) {
fp = find_func(rfname);
}
@@ -1481,29 +1537,7 @@ theend:
// Report an error unless the argument evaluation or function call has been
// cancelled due to an aborting error, an interrupt, or an exception.
if (!aborting()) {
- 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;
- }
+ user_func_error(error, (name != NULL) ? name : funcname);
}
while (argv_clear > 0) {
@@ -2854,7 +2888,7 @@ void ex_call(exarg_T *eap)
curwin->w_cursor.coladd = 0;
}
arg = startarg;
- if (get_func_tv(name, (int)STRLEN(name), &rettv, &arg,
+ if (get_func_tv(name, -1, &rettv, &arg,
eap->line1, eap->line2, &doesrange,
true, partial, fudi.fd_dict) == FAIL) {
failed = true;
@@ -2886,8 +2920,10 @@ void ex_call(exarg_T *eap)
if (!failed || eap->cstack->cs_trylevel > 0) {
// Check for trailing illegal characters and a following command.
if (!ends_excmd(*arg)) {
- emsg_severe = TRUE;
- EMSG(_(e_trailing));
+ if (!failed) {
+ emsg_severe = true;
+ EMSG(_(e_trailing));
+ }
} else {
eap->nextcmd = check_nextcmd(arg);
}
@@ -3348,9 +3384,13 @@ bool set_ref_in_previous_funccal(int copyID)
{
bool abort = false;
- for (funccall_T *fc = previous_funccal; fc != NULL; fc = fc->caller) {
- abort = abort || set_ref_in_ht(&fc->l_vars.dv_hashtab, copyID + 1, NULL);
- abort = abort || set_ref_in_ht(&fc->l_avars.dv_hashtab, copyID + 1, NULL);
+ for (funccall_T *fc = previous_funccal; !abort && 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);
}
return abort;
}
@@ -3361,9 +3401,11 @@ static bool set_ref_in_funccal(funccall_T *fc, int copyID)
if (fc->fc_copyID != copyID) {
fc->fc_copyID = copyID;
- abort = abort || set_ref_in_ht(&fc->l_vars.dv_hashtab, copyID, NULL);
- abort = abort || set_ref_in_ht(&fc->l_avars.dv_hashtab, copyID, NULL);
- abort = abort || set_ref_in_func(NULL, fc->func, 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);
}
return abort;
}
@@ -3373,12 +3415,13 @@ bool set_ref_in_call_stack(int copyID)
{
bool abort = false;
- for (funccall_T *fc = current_funccal; fc != NULL; fc = fc->caller) {
+ for (funccall_T *fc = current_funccal; !abort && fc != NULL;
+ fc = fc->caller) {
abort = abort || set_ref_in_funccal(fc, copyID);
}
// Also go through the funccal_stack.
- for (funccal_entry_T *entry = funccal_stack; entry != NULL;
+ for (funccal_entry_T *entry = funccal_stack; !abort && entry != NULL;
entry = entry->next) {
for (funccall_T *fc = entry->top_funccal; !abort && fc != NULL;
fc = fc->caller) {
@@ -3457,12 +3500,7 @@ bool set_ref_in_func(char_u *name, ufunc_T *fp_in, int copyID)
char_u *register_cfunc(cfunc_T cb, cfunc_free_T cb_free, void *state)
{
char_u *name = get_lambda_name();
- ufunc_T *fp = NULL;
-
- fp = xcalloc(1, offsetof(ufunc_T, uf_name) + STRLEN(name) + 1);
- if (fp == NULL) {
- return NULL;
- }
+ ufunc_T *fp = xcalloc(1, offsetof(ufunc_T, uf_name) + STRLEN(name) + 1);
fp->uf_refcount = 1;
fp->uf_varargs = true;