0
0
mirror of https://github.com/vim/vim.git synced 2025-07-04 23:07:33 -04:00

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.
This commit is contained in:
Bram Moolenaar 2019-08-03 18:17:11 +02:00
parent 749fa0af85
commit c6538bcc1c
12 changed files with 134 additions and 112 deletions

View File

@ -341,7 +341,6 @@ invoke_listeners(buf_T *buf)
{ {
listener_T *lnr; listener_T *lnr;
typval_T rettv; typval_T rettv;
int dummy;
typval_T argv[6]; typval_T argv[6];
listitem_T *li; listitem_T *li;
linenr_T start = MAXLNUM; linenr_T start = MAXLNUM;
@ -389,8 +388,7 @@ invoke_listeners(buf_T *buf)
for (lnr = buf->b_listener; lnr != NULL; lnr = lnr->lr_next) for (lnr = buf->b_listener; lnr != NULL; lnr = lnr->lr_next)
{ {
call_callback(&lnr->lr_callback, -1, &rettv, call_callback(&lnr->lr_callback, -1, &rettv, 5, argv);
5, argv, NULL, 0L, 0L, &dummy, TRUE, NULL);
clear_tv(&rettv); clear_tv(&rettv);
} }

View File

@ -1633,7 +1633,6 @@ channel_write_new_lines(buf_T *buf)
invoke_callback(channel_T *channel, callback_T *callback, typval_T *argv) invoke_callback(channel_T *channel, callback_T *callback, typval_T *argv)
{ {
typval_T rettv; typval_T rettv;
int dummy;
if (safe_to_invoke_callback == 0) if (safe_to_invoke_callback == 0)
iemsg("INTERNAL: Invoking callback when it is not safe"); iemsg("INTERNAL: Invoking callback when it is not safe");
@ -1641,8 +1640,7 @@ invoke_callback(channel_T *channel, callback_T *callback, typval_T *argv)
argv[0].v_type = VAR_CHANNEL; argv[0].v_type = VAR_CHANNEL;
argv[0].vval.v_channel = channel; argv[0].vval.v_channel = channel;
call_callback(callback, -1, &rettv, 2, argv, NULL, call_callback(callback, -1, &rettv, 2, argv);
0L, 0L, &dummy, TRUE, NULL);
clear_tv(&rettv); clear_tv(&rettv);
channel_need_redraw = TRUE; channel_need_redraw = TRUE;
} }
@ -3029,7 +3027,6 @@ channel_close(channel_T *channel, int invoke_close_cb)
{ {
typval_T argv[1]; typval_T argv[1];
typval_T rettv; typval_T rettv;
int dummy;
/* Increment the refcount to avoid the channel being freed /* Increment the refcount to avoid the channel being freed
* halfway. */ * halfway. */
@ -3038,8 +3035,7 @@ channel_close(channel_T *channel, int invoke_close_cb)
(char *)channel->ch_close_cb.cb_name); (char *)channel->ch_close_cb.cb_name);
argv[0].v_type = VAR_CHANNEL; argv[0].v_type = VAR_CHANNEL;
argv[0].vval.v_channel = channel; argv[0].vval.v_channel = channel;
call_callback(&channel->ch_close_cb, -1, call_callback(&channel->ch_close_cb, -1, &rettv, 1, argv);
&rettv, 1, argv, NULL, 0L, 0L, &dummy, TRUE, NULL);
clear_tv(&rettv); clear_tv(&rettv);
channel_need_redraw = TRUE; channel_need_redraw = TRUE;
@ -5541,7 +5537,6 @@ job_cleanup(job_T *job)
{ {
typval_T argv[3]; typval_T argv[3];
typval_T rettv; typval_T rettv;
int dummy;
/* Invoke the exit callback. Make sure the refcount is > 0. */ /* Invoke the exit callback. Make sure the refcount is > 0. */
ch_log(job->jv_channel, "Invoking exit callback %s", ch_log(job->jv_channel, "Invoking exit callback %s",
@ -5551,8 +5546,7 @@ job_cleanup(job_T *job)
argv[0].vval.v_job = job; argv[0].vval.v_job = job;
argv[1].v_type = VAR_NUMBER; argv[1].v_type = VAR_NUMBER;
argv[1].vval.v_number = job->jv_exitval; argv[1].vval.v_number = job->jv_exitval;
call_callback(&job->jv_exit_cb, -1, call_callback(&job->jv_exit_cb, -1, &rettv, 2, argv);
&rettv, 2, argv, NULL, 0L, 0L, &dummy, TRUE, NULL);
clear_tv(&rettv); clear_tv(&rettv);
--job->jv_refcount; --job->jv_refcount;
channel_need_redraw = TRUE; channel_need_redraw = TRUE;
@ -6036,7 +6030,6 @@ job_stop(job_T *job, typval_T *argvars, char *type)
invoke_prompt_callback(void) invoke_prompt_callback(void)
{ {
typval_T rettv; typval_T rettv;
int dummy;
typval_T argv[2]; typval_T argv[2];
char_u *text; char_u *text;
char_u *prompt; char_u *prompt;
@ -6059,8 +6052,7 @@ invoke_prompt_callback(void)
argv[0].vval.v_string = vim_strsave(text); argv[0].vval.v_string = vim_strsave(text);
argv[1].v_type = VAR_UNKNOWN; argv[1].v_type = VAR_UNKNOWN;
call_callback(&curbuf->b_prompt_callback, -1, call_callback(&curbuf->b_prompt_callback, -1, &rettv, 1, argv);
&rettv, 1, argv, NULL, 0L, 0L, &dummy, TRUE, NULL);
clear_tv(&argv[0]); clear_tv(&argv[0]);
clear_tv(&rettv); clear_tv(&rettv);
} }
@ -6072,7 +6064,6 @@ invoke_prompt_callback(void)
invoke_prompt_interrupt(void) invoke_prompt_interrupt(void)
{ {
typval_T rettv; typval_T rettv;
int dummy;
typval_T argv[1]; typval_T argv[1];
if (curbuf->b_prompt_interrupt.cb_name == NULL if (curbuf->b_prompt_interrupt.cb_name == NULL
@ -6081,8 +6072,7 @@ invoke_prompt_interrupt(void)
argv[0].v_type = VAR_UNKNOWN; argv[0].v_type = VAR_UNKNOWN;
got_int = FALSE; // don't skip executing commands got_int = FALSE; // don't skip executing commands
call_callback(&curbuf->b_prompt_interrupt, -1, call_callback(&curbuf->b_prompt_interrupt, -1, &rettv, 0, argv);
&rettv, 0, argv, NULL, 0L, 0L, &dummy, TRUE, NULL);
clear_tv(&rettv); clear_tv(&rettv);
return TRUE; return TRUE;
} }

View File

@ -765,16 +765,17 @@ eval1_emsg(char_u **arg, typval_T *rettv, int evaluate)
eval_expr_typval(typval_T *expr, typval_T *argv, int argc, typval_T *rettv) eval_expr_typval(typval_T *expr, typval_T *argv, int argc, typval_T *rettv)
{ {
char_u *s; char_u *s;
int dummy;
char_u buf[NUMBUFLEN]; char_u buf[NUMBUFLEN];
funcexe_T funcexe;
if (expr->v_type == VAR_FUNC) if (expr->v_type == VAR_FUNC)
{ {
s = expr->vval.v_string; s = expr->vval.v_string;
if (s == NULL || *s == NUL) if (s == NULL || *s == NUL)
return FAIL; return FAIL;
if (call_func(s, -1, rettv, argc, argv, NULL, vim_memset(&funcexe, 0, sizeof(funcexe));
0L, 0L, &dummy, TRUE, NULL, NULL) == FAIL) funcexe.evaluate = TRUE;
if (call_func(s, -1, rettv, argc, argv, &funcexe) == FAIL)
return FAIL; return FAIL;
} }
else if (expr->v_type == VAR_PARTIAL) else if (expr->v_type == VAR_PARTIAL)
@ -784,8 +785,10 @@ eval_expr_typval(typval_T *expr, typval_T *argv, int argc, typval_T *rettv)
s = partial_name(partial); s = partial_name(partial);
if (s == NULL || *s == NUL) if (s == NULL || *s == NUL)
return FAIL; return FAIL;
if (call_func(s, -1, rettv, argc, argv, NULL, vim_memset(&funcexe, 0, sizeof(funcexe));
0L, 0L, &dummy, TRUE, partial, NULL) == FAIL) funcexe.evaluate = TRUE;
funcexe.partial = partial;
if (call_func(s, -1, rettv, argc, argv, &funcexe) == FAIL)
return FAIL; return FAIL;
} }
else else
@ -1092,13 +1095,15 @@ call_vim_function(
typval_T *argv, typval_T *argv,
typval_T *rettv) typval_T *rettv)
{ {
int doesrange;
int ret; int ret;
funcexe_T funcexe;
rettv->v_type = VAR_UNKNOWN; /* clear_tv() uses this */ rettv->v_type = VAR_UNKNOWN; /* clear_tv() uses this */
ret = call_func(func, -1, rettv, argc, argv, NULL, vim_memset(&funcexe, 0, sizeof(funcexe));
curwin->w_cursor.lnum, curwin->w_cursor.lnum, funcexe.firstline = curwin->w_cursor.lnum;
&doesrange, TRUE, NULL, NULL); funcexe.lastline = curwin->w_cursor.lnum;
funcexe.evaluate = TRUE;
ret = call_func(func, -1, rettv, argc, argv, &funcexe);
if (ret == FAIL) if (ret == FAIL)
clear_tv(rettv); clear_tv(rettv);
@ -4681,10 +4686,19 @@ eval7(
if (s == NULL) if (s == NULL)
ret = FAIL; ret = FAIL;
else else
/* Invoke the function. */ {
ret = get_func_tv(s, len, rettv, arg, funcexe_T funcexe;
curwin->w_cursor.lnum, curwin->w_cursor.lnum,
&len, evaluate, partial, NULL); // Invoke the function.
funcexe.argv_func = NULL;
funcexe.firstline = curwin->w_cursor.lnum;
funcexe.lastline = curwin->w_cursor.lnum;
funcexe.doesrange = &len;
funcexe.evaluate = evaluate;
funcexe.partial = partial;
funcexe.selfdict = NULL;
ret = get_func_tv(s, len, rettv, arg, &funcexe);
}
vim_free(s); vim_free(s);
/* If evaluate is FALSE rettv->v_type was not set in /* If evaluate is FALSE rettv->v_type was not set in
@ -7359,7 +7373,6 @@ handle_subscript(
int ret = OK; int ret = OK;
dict_T *selfdict = NULL; dict_T *selfdict = NULL;
char_u *s; char_u *s;
int len;
typval_T functv; typval_T functv;
// "." is ".name" lookup when we found a dict or when evaluating and // "." is ".name" lookup when we found a dict or when evaluating and
@ -7377,6 +7390,7 @@ handle_subscript(
if (**arg == '(') if (**arg == '(')
{ {
partial_T *pt = NULL; partial_T *pt = NULL;
funcexe_T funcexe;
/* need to copy the funcref so that we can clear rettv */ /* need to copy the funcref so that we can clear rettv */
if (evaluate) if (evaluate)
@ -7395,9 +7409,15 @@ handle_subscript(
} }
else else
s = (char_u *)""; s = (char_u *)"";
ret = get_func_tv(s, -1, rettv, arg,
curwin->w_cursor.lnum, curwin->w_cursor.lnum, funcexe.argv_func = NULL;
&len, evaluate, pt, selfdict); funcexe.firstline = curwin->w_cursor.lnum;
funcexe.lastline = curwin->w_cursor.lnum;
funcexe.doesrange = NULL;
funcexe.evaluate = evaluate;
funcexe.partial = pt;
funcexe.selfdict = selfdict;
ret = get_func_tv(s, -1, rettv, arg, &funcexe);
/* Clear the funcref afterwards, so that deleting it while /* Clear the funcref afterwards, so that deleting it while
* evaluating the arguments is possible (see test55). */ * evaluating the arguments is possible (see test55). */

View File

@ -110,15 +110,13 @@ create_timer(long msec, int repeat)
timer_callback(timer_T *timer) timer_callback(timer_T *timer)
{ {
typval_T rettv; typval_T rettv;
int dummy;
typval_T argv[2]; typval_T argv[2];
argv[0].v_type = VAR_NUMBER; argv[0].v_type = VAR_NUMBER;
argv[0].vval.v_number = (varnumber_T)timer->tr_id; argv[0].vval.v_number = (varnumber_T)timer->tr_id;
argv[1].v_type = VAR_UNKNOWN; argv[1].v_type = VAR_UNKNOWN;
call_callback(&timer->tr_callback, -1, call_callback(&timer->tr_callback, -1, &rettv, 1, argv);
&rettv, 1, argv, NULL, 0L, 0L, &dummy, TRUE, NULL);
clear_tv(&rettv); clear_tv(&rettv);
} }

View File

@ -1284,9 +1284,9 @@ item_compare2(const void *s1, const void *s2)
int res; int res;
typval_T rettv; typval_T rettv;
typval_T argv[3]; typval_T argv[3];
int dummy;
char_u *func_name; char_u *func_name;
partial_T *partial = sortinfo->item_compare_partial; partial_T *partial = sortinfo->item_compare_partial;
funcexe_T funcexe;
/* shortcut after failure in previous call; compare all items equal */ /* shortcut after failure in previous call; compare all items equal */
if (sortinfo->item_compare_func_err) if (sortinfo->item_compare_func_err)
@ -1306,8 +1306,11 @@ item_compare2(const void *s1, const void *s2)
copy_tv(&si2->item->li_tv, &argv[1]); copy_tv(&si2->item->li_tv, &argv[1]);
rettv.v_type = VAR_UNKNOWN; /* clear_tv() uses this */ rettv.v_type = VAR_UNKNOWN; /* clear_tv() uses this */
res = call_func(func_name, -1, &rettv, 2, argv, NULL, 0L, 0L, &dummy, TRUE, vim_memset(&funcexe, 0, sizeof(funcexe));
partial, sortinfo->item_compare_selfdict); funcexe.evaluate = TRUE;
funcexe.partial = partial;
funcexe.selfdict = sortinfo->item_compare_selfdict;
res = call_func(func_name, -1, &rettv, 2, argv, &funcexe);
clear_tv(&argv[0]); clear_tv(&argv[0]);
clear_tv(&argv[1]); clear_tv(&argv[1]);

View File

@ -1673,7 +1673,6 @@ f_popup_beval(typval_T *argvars, typval_T *rettv)
invoke_popup_callback(win_T *wp, typval_T *result) invoke_popup_callback(win_T *wp, typval_T *result)
{ {
typval_T rettv; typval_T rettv;
int dummy;
typval_T argv[3]; typval_T argv[3];
argv[0].v_type = VAR_NUMBER; argv[0].v_type = VAR_NUMBER;
@ -1689,8 +1688,7 @@ invoke_popup_callback(win_T *wp, typval_T *result)
argv[2].v_type = VAR_UNKNOWN; argv[2].v_type = VAR_UNKNOWN;
call_callback(&wp->w_close_cb, -1, call_callback(&wp->w_close_cb, -1, &rettv, 2, argv);
&rettv, 2, argv, NULL, 0L, 0L, &dummy, TRUE, NULL);
if (result != NULL) if (result != NULL)
clear_tv(&argv[1]); clear_tv(&argv[1]);
clear_tv(&rettv); clear_tv(&rettv);
@ -2455,7 +2453,6 @@ invoke_popup_filter(win_T *wp, int c)
{ {
int res; int res;
typval_T rettv; typval_T rettv;
int dummy;
typval_T argv[3]; typval_T argv[3];
char_u buf[NUMBUFLEN]; char_u buf[NUMBUFLEN];
linenr_T old_lnum = wp->w_cursor.lnum; linenr_T old_lnum = wp->w_cursor.lnum;
@ -2481,8 +2478,7 @@ invoke_popup_filter(win_T *wp, int c)
argv[2].v_type = VAR_UNKNOWN; argv[2].v_type = VAR_UNKNOWN;
// NOTE: The callback might close the popup, thus make "wp" invalid. // NOTE: The callback might close the popup, thus make "wp" invalid.
call_callback(&wp->w_filter_cb, -1, call_callback(&wp->w_filter_cb, -1, &rettv, 2, argv);
&rettv, 2, argv, NULL, 0L, 0L, &dummy, TRUE, NULL);
if (win_valid_popup(wp) && old_lnum != wp->w_cursor.lnum) if (win_valid_popup(wp) && old_lnum != wp->w_cursor.lnum)
popup_highlight_curline(wp); popup_highlight_curline(wp);

View File

@ -3,15 +3,15 @@ void func_init(void);
hashtab_T *func_tbl_get(void); hashtab_T *func_tbl_get(void);
int get_lambda_tv(char_u **arg, typval_T *rettv, int evaluate); int get_lambda_tv(char_u **arg, typval_T *rettv, int evaluate);
char_u *deref_func_name(char_u *name, int *lenp, partial_T **partialp, int no_autoload); char_u *deref_func_name(char_u *name, int *lenp, partial_T **partialp, int no_autoload);
int get_func_tv(char_u *name, int len, typval_T *rettv, char_u **arg, linenr_T firstline, linenr_T lastline, int *doesrange, int evaluate, partial_T *partial, dict_T *selfdict); int get_func_tv(char_u *name, int len, typval_T *rettv, char_u **arg, funcexe_T *funcexe);
ufunc_T *find_func(char_u *name); ufunc_T *find_func(char_u *name);
void save_funccal(funccal_entry_T *entry); void save_funccal(funccal_entry_T *entry);
void restore_funccal(void); void restore_funccal(void);
funccall_T *get_current_funccal(void); funccall_T *get_current_funccal(void);
void free_all_functions(void); void free_all_functions(void);
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);
int call_callback(callback_T *callback, int len, typval_T *rettv, int argcount, typval_T *argvars, int (*argv_func)(int, typval_T *, int), linenr_T firstline, linenr_T lastline, int *doesrange, int evaluate, dict_T *selfdict); int call_callback(callback_T *callback, int len, typval_T *rettv, int argcount, typval_T *argvars);
int call_func(char_u *funcname, int len, typval_T *rettv, int argcount_in, typval_T *argvars_in, int (*argv_func)(int, typval_T *, int), linenr_T firstline, linenr_T lastline, int *doesrange, int evaluate, partial_T *partial, dict_T *selfdict_in); int call_func(char_u *funcname, int len, typval_T *rettv, int argcount_in, typval_T *argvars_in, funcexe_T *funcexe);
char_u *trans_function_name(char_u **pp, int skip, int flags, funcdict_T *fdp, partial_T **partial); char_u *trans_function_name(char_u **pp, int skip, int flags, funcdict_T *fdp, partial_T **partial);
void ex_function(exarg_T *eap); void ex_function(exarg_T *eap);
int eval_fname_script(char_u *p); int eval_fname_script(char_u *p);

View File

@ -7416,31 +7416,31 @@ vim_regsub_both(
if (expr != NULL) if (expr != NULL)
{ {
typval_T argv[2]; typval_T argv[2];
int dummy;
char_u buf[NUMBUFLEN]; char_u buf[NUMBUFLEN];
typval_T rettv; typval_T rettv;
staticList10_T matchList; staticList10_T matchList;
funcexe_T funcexe;
rettv.v_type = VAR_STRING; rettv.v_type = VAR_STRING;
rettv.vval.v_string = NULL; rettv.vval.v_string = NULL;
argv[0].v_type = VAR_LIST; argv[0].v_type = VAR_LIST;
argv[0].vval.v_list = &matchList.sl_list; argv[0].vval.v_list = &matchList.sl_list;
matchList.sl_list.lv_len = 0; matchList.sl_list.lv_len = 0;
vim_memset(&funcexe, 0, sizeof(funcexe));
funcexe.argv_func = fill_submatch_list;
funcexe.evaluate = TRUE;
if (expr->v_type == VAR_FUNC) if (expr->v_type == VAR_FUNC)
{ {
s = expr->vval.v_string; s = expr->vval.v_string;
call_func(s, -1, &rettv, call_func(s, -1, &rettv, 1, argv, &funcexe);
1, argv, fill_submatch_list,
0L, 0L, &dummy, TRUE, NULL, NULL);
} }
else if (expr->v_type == VAR_PARTIAL) else if (expr->v_type == VAR_PARTIAL)
{ {
partial_T *partial = expr->vval.v_partial; partial_T *partial = expr->vval.v_partial;
s = partial_name(partial); s = partial_name(partial);
call_func(s, -1, &rettv, funcexe.partial = partial;
1, argv, fill_submatch_list, call_func(s, -1, &rettv, 1, argv, &funcexe);
0L, 0L, &dummy, TRUE, partial, NULL);
} }
if (matchList.sl_list.lv_len > 0) if (matchList.sl_list.lv_len > 0)
/* fill_submatch_list() was called */ /* fill_submatch_list() was called */

View File

@ -1517,6 +1517,22 @@ struct funccall_S
// "func" // "func"
}; };
// Struct passed between functions dealing with function call execution.
//
// "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)
//
typedef struct {
int (* argv_func)(int, typval_T *, int);
linenr_T firstline; // first line of range
linenr_T lastline; // last line of range
int *doesrange; // if not NULL: return: function handled range
int evaluate; // actually evaluate expressions
partial_T *partial; // for extra arguments
dict_T *selfdict; // Dictionary for "self"
} funcexe_T;
/* /*
* Struct used by trans_function_name() * Struct used by trans_function_name()
*/ */

View File

@ -3772,7 +3772,7 @@ handle_call_command(term_T *term, channel_T *channel, listitem_T *item)
char_u *func; char_u *func;
typval_T argvars[2]; typval_T argvars[2];
typval_T rettv; typval_T rettv;
int doesrange; funcexe_T funcexe;
if (item->li_next == NULL) if (item->li_next == NULL)
{ {
@ -3790,11 +3790,11 @@ handle_call_command(term_T *term, channel_T *channel, listitem_T *item)
argvars[0].v_type = VAR_NUMBER; argvars[0].v_type = VAR_NUMBER;
argvars[0].vval.v_number = term->tl_buffer->b_fnum; argvars[0].vval.v_number = term->tl_buffer->b_fnum;
argvars[1] = item->li_next->li_tv; argvars[1] = item->li_next->li_tv;
if (call_func(func, -1, &rettv, vim_memset(&funcexe, 0, sizeof(funcexe));
2, argvars, /* argv_func */ NULL, funcexe.firstline = 1L;
/* firstline */ 1, /* lastline */ 1, funcexe.lastline = 1L;
&doesrange, /* evaluate */ TRUE, funcexe.evaluate = TRUE;
/* partial */ NULL, /* selfdict */ NULL) == OK) if (call_func(func, -1, &rettv, 2, argvars, &funcexe) == OK)
{ {
clear_tv(&rettv); clear_tv(&rettv);
ch_log(channel, "Function %s called", func); ch_log(channel, "Function %s called", func);

View File

@ -432,12 +432,7 @@ get_func_tv(
int len, // length of "name" or -1 to use strlen() int len, // length of "name" or -1 to use strlen()
typval_T *rettv, typval_T *rettv,
char_u **arg, // argument, pointing to the '(' char_u **arg, // argument, pointing to the '('
linenr_T firstline, // first line of range funcexe_T *funcexe) // various values
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; char_u *argp;
int ret = OK; int ret = OK;
@ -448,12 +443,13 @@ get_func_tv(
* Get the arguments. * Get the arguments.
*/ */
argp = *arg; 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 ',' */ argp = skipwhite(argp + 1); /* skip the '(' or ',' */
if (*argp == ')' || *argp == ',' || *argp == NUL) if (*argp == ')' || *argp == ',' || *argp == NUL)
break; break;
if (eval1(&argp, &argvars[argcount], evaluate) == FAIL) if (eval1(&argp, &argvars[argcount], funcexe->evaluate) == FAIL)
{ {
ret = FAIL; ret = FAIL;
break; break;
@ -483,8 +479,7 @@ get_func_tv(
&argvars[i]; &argvars[i];
} }
ret = call_func(name, len, rettv, argcount, argvars, NULL, ret = call_func(name, len, rettv, argcount, argvars, funcexe);
firstline, lastline, doesrange, evaluate, partial, selfdict);
funcargs.ga_len -= i; funcargs.ga_len -= i;
} }
@ -1416,7 +1411,6 @@ func_call(
listitem_T *item; listitem_T *item;
typval_T argv[MAX_FUNC_ARGS + 1]; typval_T argv[MAX_FUNC_ARGS + 1];
int argc = 0; int argc = 0;
int dummy;
int r = 0; int r = 0;
for (item = args->vval.v_list->lv_first; item != NULL; for (item = args->vval.v_list->lv_first; item != NULL;
@ -1434,9 +1428,18 @@ func_call(
} }
if (item == NULL) if (item == NULL)
r = call_func(name, -1, rettv, argc, argv, NULL, {
curwin->w_cursor.lnum, curwin->w_cursor.lnum, funcexe_T funcexe;
&dummy, TRUE, partial, selfdict);
funcexe.argv_func = NULL;
funcexe.firstline = curwin->w_cursor.lnum;
funcexe.lastline = curwin->w_cursor.lnum;
funcexe.doesrange = NULL;
funcexe.evaluate = TRUE;
funcexe.partial = partial;
funcexe.selfdict = selfdict;
r = call_func(name, -1, rettv, argc, argv, &funcexe);
}
/* Free the arguments. */ /* Free the arguments. */
while (argc > 0) while (argc > 0)
@ -1454,28 +1457,21 @@ call_callback(
int len, // length of "name" or -1 to use strlen() int len, // length of "name" or -1 to use strlen()
typval_T *rettv, // return value goes here typval_T *rettv, // return value goes here
int argcount, // number of "argvars" int argcount, // number of "argvars"
typval_T *argvars, // vars for arguments, must have "argcount" typval_T *argvars) // vars for arguments, must have "argcount"
// PLUS ONE elements! // PLUS ONE elements!
int (* argv_func)(int, typval_T *, int),
// function to fill in argvars
linenr_T firstline, // first line of range
linenr_T lastline, // last line of range
int *doesrange, // return: function handled range
int evaluate,
dict_T *selfdict) // Dictionary for "self"
{ {
funcexe_T funcexe;
vim_memset(&funcexe, 0, sizeof(funcexe));
funcexe.evaluate = TRUE;
funcexe.partial = callback->cb_partial;
return call_func(callback->cb_name, len, rettv, argcount, argvars, return call_func(callback->cb_name, len, rettv, argcount, argvars,
argv_func, firstline, lastline, doesrange, evaluate, &funcexe);
callback->cb_partial, selfdict);
} }
/* /*
* Call a function with its resolved parameters * 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 when the function can't be called, OK otherwise. * Return FAIL when the function can't be called, OK otherwise.
* Also returns OK when an error was encountered while executing the function. * Also returns OK when an error was encountered while executing the function.
*/ */
@ -1487,14 +1483,7 @@ call_func(
int argcount_in, // number of "argvars" int argcount_in, // number of "argvars"
typval_T *argvars_in, // vars for arguments, must have "argcount" typval_T *argvars_in, // vars for arguments, must have "argcount"
// PLUS ONE elements! // PLUS ONE elements!
int (* argv_func)(int, typval_T *, int), funcexe_T *funcexe) // more arguments
// function to fill in argvars
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, // optional, can be NULL
dict_T *selfdict_in) // Dictionary for "self"
{ {
int ret = FAIL; int ret = FAIL;
int error = ERROR_NONE; int error = ERROR_NONE;
@ -1506,9 +1495,10 @@ call_func(
char_u *name; char_u *name;
int argcount = argcount_in; int argcount = argcount_in;
typval_T *argvars = argvars_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 */ typval_T argv[MAX_FUNC_ARGS + 1]; /* used when "partial" is not NULL */
int argv_clear = 0; int argv_clear = 0;
partial_T *partial = funcexe->partial;
// Make a copy of the name, if it comes from a funcref variable it could // Make a copy of the name, if it comes from a funcref variable it could
// be changed or deleted in the called function. // be changed or deleted in the called function.
@ -1518,15 +1508,15 @@ call_func(
fname = fname_trans_sid(name, fname_buf, &tofree, &error); fname = fname_trans_sid(name, fname_buf, &tofree, &error);
*doesrange = FALSE; if (funcexe->doesrange != NULL)
*funcexe->doesrange = FALSE;
if (partial != NULL) if (partial != NULL)
{ {
/* When the function has a partial with a dict and there is a dict /* When the function has a partial with a dict and there is a dict
* argument, use the dict argument. That is backwards compatible. * argument, use the dict argument. That is backwards compatible.
* When the dict was bound explicitly use the one from the partial. */ * When the dict was bound explicitly use the one from the partial. */
if (partial->pt_dict != NULL if (partial->pt_dict != NULL && (selfdict == NULL || !partial->pt_auto))
&& (selfdict_in == NULL || !partial->pt_auto))
selfdict = partial->pt_dict; selfdict = partial->pt_dict;
if (error == ERROR_NONE && partial->pt_argc > 0) if (error == ERROR_NONE && partial->pt_argc > 0)
{ {
@ -1542,7 +1532,7 @@ call_func(
/* /*
* Execute the function if executing and no errors were detected. * Execute the function if executing and no errors were detected.
*/ */
if (!evaluate) if (!funcexe->evaluate)
{ {
// Not evaluating, which means the return value is unknown. This // Not evaluating, which means the return value is unknown. This
// matters for giving error messages. // matters for giving error messages.
@ -1590,11 +1580,12 @@ call_func(
error = ERROR_DELETED; error = ERROR_DELETED;
else if (fp != NULL) else if (fp != NULL)
{ {
if (argv_func != NULL) if (funcexe->argv_func != NULL)
argcount = argv_func(argcount, argvars, fp->uf_args.ga_len); argcount = funcexe->argv_func(argcount, argvars,
fp->uf_args.ga_len);
if (fp->uf_flags & FC_RANGE) if (fp->uf_flags & FC_RANGE && funcexe->doesrange != NULL)
*doesrange = TRUE; *funcexe->doesrange = TRUE;
if (argcount < fp->uf_args.ga_len - fp->uf_def_args.ga_len) if (argcount < fp->uf_args.ga_len - fp->uf_def_args.ga_len)
error = ERROR_TOOFEW; error = ERROR_TOOFEW;
else if (!fp->uf_varargs && argcount > fp->uf_args.ga_len) else if (!fp->uf_varargs && argcount > fp->uf_args.ga_len)
@ -1621,7 +1612,7 @@ call_func(
} }
++fp->uf_calls; ++fp->uf_calls;
call_user_func(fp, argcount, argvars, rettv, call_user_func(fp, argcount, argvars, rettv,
firstline, lastline, funcexe->firstline, funcexe->lastline,
(fp->uf_flags & FC_DICT) ? selfdict : NULL); (fp->uf_flags & FC_DICT) ? selfdict : NULL);
if (--fp->uf_calls <= 0 && fp->uf_refcount <= 0) if (--fp->uf_calls <= 0 && fp->uf_refcount <= 0)
/* Function was unreferenced while being used, free it /* Function was unreferenced while being used, free it
@ -3112,6 +3103,8 @@ ex_call(exarg_T *eap)
lnum = eap->line1; lnum = eap->line1;
for ( ; lnum <= eap->line2; ++lnum) for ( ; lnum <= eap->line2; ++lnum)
{ {
funcexe_T funcexe;
if (!eap->skip && eap->addr_count > 0) if (!eap->skip && eap->addr_count > 0)
{ {
if (lnum > curbuf->b_ml.ml_line_count) if (lnum > curbuf->b_ml.ml_line_count)
@ -3126,9 +3119,15 @@ ex_call(exarg_T *eap)
curwin->w_cursor.coladd = 0; curwin->w_cursor.coladd = 0;
} }
arg = startarg; arg = startarg;
if (get_func_tv(name, -1, &rettv, &arg,
eap->line1, eap->line2, &doesrange, funcexe.argv_func = NULL;
!eap->skip, partial, fudi.fd_dict) == FAIL) funcexe.firstline = eap->line1;
funcexe.lastline = eap->line2;
funcexe.doesrange = &doesrange;
funcexe.evaluate = !eap->skip;
funcexe.partial = partial;
funcexe.selfdict = fudi.fd_dict;
if (get_func_tv(name, -1, &rettv, &arg, &funcexe) == FAIL)
{ {
failed = TRUE; failed = TRUE;
break; break;

View File

@ -773,6 +773,8 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
1800,
/**/ /**/
1799, 1799,
/**/ /**/