summaryrefslogtreecommitdiff
path: root/src/vim9execute.c
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2021-04-19 16:48:48 +0200
committerBram Moolenaar <Bram@vim.org>2021-04-19 16:48:48 +0200
commit4c13721482d7786f92f5a56e43b0f5c499264b7e (patch)
tree2aae28c81b61721cb9ecc5d9aee66bb51d67e371 /src/vim9execute.c
parente8209b91b9974da95899b51dba4058b411d04d5b (diff)
downloadvim-git-4c13721482d7786f92f5a56e43b0f5c499264b7e.tar.gz
patch 8.2.2784: Vim9: cannot use \=expr in :substitutev8.2.2784
Problem: Vim9: cannot use \=expr in :substitute. Solution: Compile the expression into instructions and execute them when invoked.
Diffstat (limited to 'src/vim9execute.c')
-rw-r--r--src/vim9execute.c1507
1 files changed, 816 insertions, 691 deletions
diff --git a/src/vim9execute.c b/src/vim9execute.c
index 60b58f98a..6a11e8a6b 100644
--- a/src/vim9execute.c
+++ b/src/vim9execute.c
@@ -34,6 +34,14 @@ typedef struct {
int tcd_return; // when TRUE return from end of :finally
} trycmd_T;
+// Data local to a function.
+// On a function call, if not empty, is saved on the stack and restored when
+// returning.
+typedef struct {
+ int floc_restore_cmdmod;
+ cmdmod_T floc_save_cmdmod;
+ int floc_restore_cmdmod_stacklen;
+} funclocal_T;
// A stack is used to store:
// - arguments passed to a :def function
@@ -60,8 +68,10 @@ typedef struct {
struct ectx_S {
garray_T ec_stack; // stack of typval_T values
int ec_frame_idx; // index in ec_stack: context of ec_dfunc_idx
+ int ec_initial_frame_idx; // frame index when called
outer_T *ec_outer; // outer scope used for closures, allocated
+ funclocal_T ec_funclocal;
garray_T ec_trystack; // stack of trycmd_T values
int ec_in_catch; // when TRUE in catch or finally block
@@ -71,6 +81,10 @@ struct ectx_S {
int ec_iidx; // index in ec_instr: instruction to execute
garray_T ec_funcrefs; // partials that might be a closure
+
+ int ec_did_emsg_before;
+ int ec_trylevel_at_start;
+ where_T ec_where;
};
#ifdef FEAT_PROFILE
@@ -125,15 +139,6 @@ exe_newlist(int count, ectx_T *ectx)
return OK;
}
-// Data local to a function.
-// On a function call, if not empty, is saved on the stack and restored when
-// returning.
-typedef struct {
- int floc_restore_cmdmod;
- cmdmod_T floc_save_cmdmod;
- int floc_restore_cmdmod_stacklen;
-} funclocal_T;
-
/*
* Call compiled function "cdf_idx" from compiled code.
* This adds a stack frame and sets the instruction pointer to the start of the
@@ -154,7 +159,6 @@ call_dfunc(
int cdf_idx,
partial_T *pt,
int argcount_arg,
- funclocal_T *funclocal,
ectx_T *ectx)
{
int argcount = argcount_arg;
@@ -254,13 +258,13 @@ call_dfunc(
return FAIL;
// Only make a copy of funclocal if it contains something to restore.
- if (funclocal->floc_restore_cmdmod)
+ if (ectx->ec_funclocal.floc_restore_cmdmod)
{
floc = ALLOC_ONE(funclocal_T);
if (floc == NULL)
return FAIL;
- *floc = *funclocal;
- funclocal->floc_restore_cmdmod = FALSE;
+ *floc = ectx->ec_funclocal;
+ ectx->ec_funclocal.floc_restore_cmdmod = FALSE;
}
// Move the vararg-list to below the missing optional arguments.
@@ -527,7 +531,7 @@ funcstack_check_refcount(funcstack_T *funcstack)
* Return from the current function.
*/
static int
-func_return(funclocal_T *funclocal, ectx_T *ectx)
+func_return(ectx_T *ectx)
{
int idx;
int ret_idx;
@@ -598,10 +602,10 @@ func_return(funclocal_T *funclocal, ectx_T *ectx)
ectx->ec_instr = INSTRUCTIONS(prev_dfunc);
if (floc == NULL)
- funclocal->floc_restore_cmdmod = FALSE;
+ ectx->ec_funclocal.floc_restore_cmdmod = FALSE;
else
{
- *funclocal = *floc;
+ ectx->ec_funclocal = *floc;
vim_free(floc);
}
@@ -698,7 +702,6 @@ call_ufunc(
ufunc_T *ufunc,
partial_T *pt,
int argcount,
- funclocal_T *funclocal,
ectx_T *ectx,
isn_T *iptr)
{
@@ -738,7 +741,7 @@ call_ufunc(
iptr->isn_arg.dfunc.cdf_idx = ufunc->uf_dfunc_idx;
iptr->isn_arg.dfunc.cdf_argcount = argcount;
}
- return call_dfunc(ufunc->uf_dfunc_idx, pt, argcount, funclocal, ectx);
+ return call_dfunc(ufunc->uf_dfunc_idx, pt, argcount, ectx);
}
if (call_prepare(argcount, argvars, ectx) == FAIL)
@@ -800,7 +803,6 @@ vim9_aborting(int prev_called_emsg)
call_by_name(
char_u *name,
int argcount,
- funclocal_T *funclocal,
ectx_T *ectx,
isn_T *iptr)
{
@@ -853,7 +855,7 @@ call_by_name(
}
}
- return call_ufunc(ufunc, NULL, argcount, funclocal, ectx, iptr);
+ return call_ufunc(ufunc, NULL, argcount, ectx, iptr);
}
return FAIL;
@@ -863,7 +865,6 @@ call_by_name(
call_partial(
typval_T *tv,
int argcount_arg,
- funclocal_T *funclocal,
ectx_T *ectx)
{
int argcount = argcount_arg;
@@ -893,7 +894,7 @@ call_partial(
}
if (pt->pt_func != NULL)
- return call_ufunc(pt->pt_func, pt, argcount, funclocal, ectx, NULL);
+ return call_ufunc(pt->pt_func, pt, argcount, ectx, NULL);
name = pt->pt_name;
}
@@ -911,7 +912,7 @@ call_partial(
if (error != FCERR_NONE)
res = FAIL;
else
- res = call_by_name(fname, argcount, funclocal, ectx, NULL);
+ res = call_by_name(fname, argcount, ectx, NULL);
vim_free(tofree);
}
@@ -1184,14 +1185,13 @@ get_script_svar(scriptref_T *sref, ectx_T *ectx)
call_eval_func(
char_u *name,
int argcount,
- funclocal_T *funclocal,
ectx_T *ectx,
isn_T *iptr)
{
int called_emsg_before = called_emsg;
int res;
- res = call_by_name(name, argcount, funclocal, ectx, iptr);
+ res = call_by_name(name, argcount, ectx, iptr);
if (res == FAIL && called_emsg == called_emsg_before)
{
dictitem_T *v;
@@ -1207,7 +1207,7 @@ call_eval_func(
semsg(_(e_unknownfunc), name);
return FAIL;
}
- return call_partial(&v->di_tv, argcount, funclocal, ectx);
+ return call_partial(&v->di_tv, argcount, ectx);
}
return res;
}
@@ -1257,255 +1257,35 @@ fill_partial_and_closure(partial_T *pt, ufunc_T *ufunc, ectx_T *ectx)
return OK;
}
-
-/*
- * Call a "def" function from old Vim script.
- * Return OK or FAIL.
- */
- int
-call_def_function(
- ufunc_T *ufunc,
- int argc_arg, // nr of arguments
- typval_T *argv, // arguments
- partial_T *partial, // optional partial for context
- typval_T *rettv) // return value
-{
- ectx_T ectx; // execution context
- int argc = argc_arg;
- int initial_frame_idx;
- typval_T *tv;
- int idx;
- int ret = FAIL;
- int defcount = ufunc->uf_args.ga_len - argc;
- sctx_T save_current_sctx = current_sctx;
- int breakcheck_count = 0;
- int did_emsg_before = did_emsg_cumul + did_emsg;
- int save_suppress_errthrow = suppress_errthrow;
- msglist_T **saved_msg_list = NULL;
- msglist_T *private_msg_list = NULL;
- funclocal_T funclocal;
- int save_emsg_silent_def = emsg_silent_def;
- int save_did_emsg_def = did_emsg_def;
- int trylevel_at_start = trylevel;
- int orig_funcdepth;
- where_T where;
+// used for substitute_instr
+typedef struct subs_expr_S {
+ ectx_T *subs_ectx;
+ isn_T *subs_instr;
+ int subs_status;
+} subs_expr_T;
// Get pointer to item in the stack.
-#define STACK_TV(idx) (((typval_T *)ectx.ec_stack.ga_data) + idx)
+#define STACK_TV(idx) (((typval_T *)ectx->ec_stack.ga_data) + idx)
// Get pointer to item at the bottom of the stack, -1 is the bottom.
#undef STACK_TV_BOT
-#define STACK_TV_BOT(idx) (((typval_T *)ectx.ec_stack.ga_data) + ectx.ec_stack.ga_len + idx)
+#define STACK_TV_BOT(idx) (((typval_T *)ectx->ec_stack.ga_data) + ectx->ec_stack.ga_len + idx)
// Get pointer to a local variable on the stack. Negative for arguments.
-#define STACK_TV_VAR(idx) (((typval_T *)ectx.ec_stack.ga_data) + ectx.ec_frame_idx + STACK_FRAME_SIZE + idx)
-
- if (ufunc->uf_def_status == UF_NOT_COMPILED
- || ufunc->uf_def_status == UF_COMPILE_ERROR
- || (func_needs_compiling(ufunc, PROFILING(ufunc))
- && compile_def_function(ufunc, FALSE, PROFILING(ufunc), NULL)
- == FAIL))
- {
- if (did_emsg_cumul + did_emsg == did_emsg_before)
- semsg(_(e_function_is_not_compiled_str),
- printable_func_name(ufunc));
- return FAIL;
- }
-
- {
- // Check the function was really compiled.
- dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data)
- + ufunc->uf_dfunc_idx;
- if (INSTRUCTIONS(dfunc) == NULL)
- {
- iemsg("using call_def_function() on not compiled function");
- return FAIL;
- }
- }
-
- // If depth of calling is getting too high, don't execute the function.
- orig_funcdepth = funcdepth_get();
- if (funcdepth_increment() == FAIL)
- return FAIL;
+#define STACK_TV_VAR(idx) (((typval_T *)ectx->ec_stack.ga_data) + ectx->ec_frame_idx + STACK_FRAME_SIZE + idx)
- CLEAR_FIELD(funclocal);
- CLEAR_FIELD(ectx);
- ectx.ec_dfunc_idx = ufunc->uf_dfunc_idx;
- ga_init2(&ectx.ec_stack, sizeof(typval_T), 500);
- if (ga_grow(&ectx.ec_stack, 20) == FAIL)
- {
- funcdepth_decrement();
- return FAIL;
- }
- ga_init2(&ectx.ec_trystack, sizeof(trycmd_T), 10);
- ga_init2(&ectx.ec_funcrefs, sizeof(partial_T *), 10);
-
- idx = argc - ufunc->uf_args.ga_len;
- if (idx > 0 && ufunc->uf_va_name == NULL)
- {
- if (idx == 1)
- emsg(_(e_one_argument_too_many));
- else
- semsg(_(e_nr_arguments_too_many), idx);
- goto failed_early;
- }
-
- // Put arguments on the stack, but no more than what the function expects.
- // A lambda can be called with more arguments than it uses.
- for (idx = 0; idx < argc
- && (ufunc->uf_va_name != NULL || idx < ufunc->uf_args.ga_len);
- ++idx)
- {
- if (idx >= ufunc->uf_args.ga_len - ufunc->uf_def_args.ga_len
- && argv[idx].v_type == VAR_SPECIAL
- && argv[idx].vval.v_number == VVAL_NONE)
- {
- // Use the default value.
- STACK_TV_BOT(0)->v_type = VAR_UNKNOWN;
- }
- else
- {
- if (ufunc->uf_arg_types != NULL && idx < ufunc->uf_args.ga_len
- && check_typval_arg_type(
- ufunc->uf_arg_types[idx], &argv[idx], idx + 1) == FAIL)
- goto failed_early;
- copy_tv(&argv[idx], STACK_TV_BOT(0));
- }
- ++ectx.ec_stack.ga_len;
- }
-
- // Turn varargs into a list. Empty list if no args.
- if (ufunc->uf_va_name != NULL)
- {
- int vararg_count = argc - ufunc->uf_args.ga_len;
-
- if (vararg_count < 0)
- vararg_count = 0;
- else
- argc -= vararg_count;
- if (exe_newlist(vararg_count, &ectx) == FAIL)
- goto failed_early;
-
- // Check the type of the list items.
- tv = STACK_TV_BOT(-1);
- if (ufunc->uf_va_type != NULL
- && ufunc->uf_va_type != &t_list_any
- && ufunc->uf_va_type->tt_member != &t_any
- && tv->vval.v_list != NULL)
- {
- type_T *expected = ufunc->uf_va_type->tt_member;
- listitem_T *li = tv->vval.v_list->lv_first;
-
- for (idx = 0; idx < vararg_count; ++idx)
- {
- if (check_typval_arg_type(expected, &li->li_tv,
- argc + idx + 1) == FAIL)
- goto failed_early;
- li = li->li_next;
- }
- }
-
- if (defcount > 0)
- // Move varargs list to below missing default arguments.
- *STACK_TV_BOT(defcount - 1) = *STACK_TV_BOT(-1);
- --ectx.ec_stack.ga_len;
- }
-
- // Make space for omitted arguments, will store default value below.
- // Any varargs list goes after them.
- if (defcount > 0)
- for (idx = 0; idx < defcount; ++idx)
- {
- STACK_TV_BOT(0)->v_type = VAR_UNKNOWN;
- ++ectx.ec_stack.ga_len;
- }
- if (ufunc->uf_va_name != NULL)
- ++ectx.ec_stack.ga_len;
-
- // Frame pointer points to just after arguments.
- ectx.ec_frame_idx = ectx.ec_stack.ga_len;
- initial_frame_idx = ectx.ec_frame_idx;
-
- {
- dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data)
- + ufunc->uf_dfunc_idx;
- ufunc_T *base_ufunc = dfunc->df_ufunc;
-
- // "uf_partial" is on the ufunc that "df_ufunc" points to, as is done
- // by copy_func().
- if (partial != NULL || base_ufunc->uf_partial != NULL)
- {
- ectx.ec_outer = ALLOC_CLEAR_ONE(outer_T);
- if (ectx.ec_outer == NULL)
- goto failed_early;
- if (partial != NULL)
- {
- if (partial->pt_outer.out_stack == NULL && current_ectx != NULL)
- {
- if (current_ectx->ec_outer != NULL)
- *ectx.ec_outer = *current_ectx->ec_outer;
- }
- else
- *ectx.ec_outer = partial->pt_outer;
- }
- else
- *ectx.ec_outer = base_ufunc->uf_partial->pt_outer;
- ectx.ec_outer->out_up_is_copy = TRUE;
- }
- }
-
- // dummy frame entries
- for (idx = 0; idx < STACK_FRAME_SIZE; ++idx)
- {
- STACK_TV(ectx.ec_stack.ga_len)->v_type = VAR_UNKNOWN;
- ++ectx.ec_stack.ga_len;
- }
-
- {
- // Reserve space for local variables and any closure reference count.
- dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data)
- + ufunc->uf_dfunc_idx;
-
- for (idx = 0; idx < dfunc->df_varcount; ++idx)
- STACK_TV_VAR(idx)->v_type = VAR_UNKNOWN;
- ectx.ec_stack.ga_len += dfunc->df_varcount;
- if (dfunc->df_has_closure)
- {
- STACK_TV_VAR(idx)->v_type = VAR_NUMBER;
- STACK_TV_VAR(idx)->vval.v_number = 0;
- ++ectx.ec_stack.ga_len;
- }
-
- ectx.ec_instr = INSTRUCTIONS(dfunc);
- }
-
- // Following errors are in the function, not the caller.
- // Commands behave like vim9script.
- estack_push_ufunc(ufunc, 1);
- current_sctx = ufunc->uf_script_ctx;
- current_sctx.sc_version = SCRIPT_VERSION_VIM9;
-
- // Use a specific location for storing error messages to be converted to an
- // exception.
- saved_msg_list = msg_list;
- msg_list = &private_msg_list;
-
- // Do turn errors into exceptions.
- suppress_errthrow = FALSE;
-
- // Do not delete the function while executing it.
- ++ufunc->uf_calls;
-
- // When ":silent!" was used before calling then we still abort the
- // function. If ":silent!" is used in the function then we don't.
- emsg_silent_def = emsg_silent;
- did_emsg_def = 0;
-
- where.wt_index = 0;
- where.wt_variable = FALSE;
+/*
+ * Execute instructions in execution context "ectx".
+ * Return OK or FAIL;
+ */
+ static int
+exec_instructions(ectx_T *ectx)
+{
+ int breakcheck_count = 0;
+ typval_T *tv;
// Start execution at the first instruction.
- ectx.ec_iidx = 0;
+ ectx->ec_iidx = 0;
for (;;)
{
@@ -1521,7 +1301,7 @@ call_def_function(
// Turn CTRL-C into an exception.
got_int = FALSE;
if (throw_exception("Vim:Interrupt", ET_INTERRUPT, NULL) == FAIL)
- goto failed;
+ return FAIL;
did_throw = TRUE;
}
@@ -1530,52 +1310,52 @@ call_def_function(
// Turn an error message into an exception.
did_emsg = FALSE;
if (throw_exception(*msg_list, ET_ERROR, NULL) == FAIL)
- goto failed;
+ return FAIL;
did_throw = TRUE;
*msg_list = NULL;
}
- if (did_throw && !ectx.ec_in_catch)
+ if (did_throw && !ectx->ec_in_catch)
{
- garray_T *trystack = &ectx.ec_trystack;
+ garray_T *trystack = &ectx->ec_trystack;
trycmd_T *trycmd = NULL;
// An exception jumps to the first catch, finally, or returns from
// the current function.
if (trystack->ga_len > 0)
trycmd = ((trycmd_T *)trystack->ga_data) + trystack->ga_len - 1;
- if (trycmd != NULL && trycmd->tcd_frame_idx == ectx.ec_frame_idx)
+ if (trycmd != NULL && trycmd->tcd_frame_idx == ectx->ec_frame_idx)
{
// jump to ":catch" or ":finally"
- ectx.ec_in_catch = TRUE;
- ectx.ec_iidx = trycmd->tcd_catch_idx;
+ ectx->ec_in_catch = TRUE;
+ ectx->ec_iidx = trycmd->tcd_catch_idx;
}
else
{
// Not inside try or need to return from current functions.
// Push a dummy return value.
- if (GA_GROW(&ectx.ec_stack, 1) == FAIL)
- goto failed;
+ if (GA_GROW(&ectx->ec_stack, 1) == FAIL)
+ return FAIL;
tv = STACK_TV_BOT(0);
tv->v_type = VAR_NUMBER;
tv->vval.v_number = 0;
- ++ectx.ec_stack.ga_len;
- if (ectx.ec_frame_idx == initial_frame_idx)
+ ++ectx->ec_stack.ga_len;
+ if (ectx->ec_frame_idx == ectx->ec_initial_frame_idx)
{
// At the toplevel we are done.
need_rethrow = TRUE;
- if (handle_closure_in_use(&ectx, FALSE) == FAIL)
- goto failed;
+ if (handle_closure_in_use(ectx, FALSE) == FAIL)
+ return FAIL;
goto done;
}
- if (func_return(&funclocal, &ectx) == FAIL)
- goto failed;
+ if (func_return(ectx) == FAIL)
+ return FAIL;
}
continue;
}
- iptr = &ectx.ec_instr[ectx.ec_iidx++];
+ iptr = &ectx->ec_instr[ectx->ec_iidx++];
switch (iptr->isn_type)
{
// execute Ex command line
@@ -1597,6 +1377,38 @@ call_def_function(
}
break;
+ // execute :substitute with an expression
+ case ISN_SUBSTITUTE:
+ {
+ subs_T *subs = &iptr->isn_arg.subs;
+ source_cookie_T cookie;
+ struct subs_expr_S *save_instr = substitute_instr;
+ struct subs_expr_S subs_instr;
+ int res;
+
+ subs_instr.subs_ectx = ectx;
+ subs_instr.subs_instr = subs->subs_instr;
+ subs_instr.subs_status = OK;
+ substitute_instr = &subs_instr;
+
+ SOURCING_LNUM = iptr->isn_lnum;
+ // This is very much like ISN_EXEC
+ CLEAR_FIELD(cookie);
+ cookie.sourcing_lnum = iptr->isn_lnum - 1;
+ res = do_cmdline(subs->subs_cmd,
+ getsourceline, &cookie,
+ DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_KEYTYPED);
+ substitute_instr = save_instr;
+
+ if (res == FAIL || did_emsg
+ || subs_instr.subs_status == FAIL)
+ goto on_error;
+ }
+ break;
+
+ case ISN_FINISH:
+ goto done;
+
// execute Ex command from pieces on the stack
case ISN_EXECCONCAT:
{
@@ -1626,7 +1438,7 @@ call_def_function(
{
cmd = alloc(len + 1);
if (cmd == NULL)
- goto failed;
+ return FAIL;
len = 0;
}
}
@@ -1643,6 +1455,7 @@ call_def_function(
int count = iptr->isn_arg.echo.echo_count;
int atstart = TRUE;
int needclr = TRUE;
+ int idx;
for (idx = 0; idx < count; ++idx)
{
@@ -1653,7 +1466,7 @@ call_def_function(
}
if (needclr)
msg_clr_eos();
- ectx.ec_stack.ga_len -= count;
+ ectx->ec_stack.ga_len -= count;
}
break;
@@ -1670,6 +1483,7 @@ call_def_function(
char_u *p;
int len;
int failed = FALSE;
+ int idx;
ga_init2(&ga, 1, 80);
for (idx = 0; idx < count; ++idx)
@@ -1702,7 +1516,7 @@ call_def_function(
}
clear_tv(tv);
}
- ectx.ec_stack.ga_len -= count;
+ ectx->ec_stack.ga_len -= count;
if (failed)
{
ga_clear(&ga);
@@ -1742,18 +1556,18 @@ call_def_function(
// load local variable or argument
case ISN_LOAD:
- if (GA_GROW(&ectx.ec_stack, 1) == FAIL)
- goto failed;
+ if (GA_GROW(&ectx->ec_stack, 1) == FAIL)
+ return FAIL;
copy_tv(STACK_TV_VAR(iptr->isn_arg.number), STACK_TV_BOT(0));
- ++ectx.ec_stack.ga_len;
+ ++ectx->ec_stack.ga_len;
break;
// load v: variable
case ISN_LOADV:
- if (GA_GROW(&ectx.ec_stack, 1) == FAIL)
- goto failed;
+ if (GA_GROW(&ectx->ec_stack, 1) == FAIL)
+ return FAIL;
copy_tv(get_vim_var_tv(iptr->isn_arg.number), STACK_TV_BOT(0));
- ++ectx.ec_stack.ga_len;
+ ++ectx->ec_stack.ga_len;
break;
// load s: variable in Vim9 script
@@ -1762,14 +1576,14 @@ call_def_function(
scriptref_T *sref = iptr->isn_arg.script.scriptref;
svar_T *sv;
- sv = get_script_svar(sref, &ectx);
+ sv = get_script_svar(sref, ectx);
if (sv == NULL)
- goto failed;
+ return FAIL;
allocate_if_null(sv->sv_tv);
- if (GA_GROW(&ectx.ec_stack, 1) == FAIL)
- goto failed;
+ if (GA_GROW(&ectx->ec_stack, 1) == FAIL)
+ return FAIL;
copy_tv(sv->sv_tv, STACK_TV_BOT(0));
- ++ectx.ec_stack.ga_len;
+ ++ectx->ec_stack.ga_len;
}
break;
@@ -1789,10 +1603,10 @@ call_def_function(
}
else
{
- if (GA_GROW(&ectx.ec_stack, 1) == FAIL)
- goto failed;
+ if (GA_GROW(&ectx->ec_stack, 1) == FAIL)
+ return FAIL;
copy_tv(&di->di_tv, STACK_TV_BOT(0));
- ++ectx.ec_stack.ga_len;
+ ++ectx->ec_stack.ga_len;
}
}
break;
@@ -1826,7 +1640,7 @@ call_def_function(
namespace = 't';
break;
default: // Cannot reach here
- goto failed;
+ return FAIL;
}
di = find_var_in_ht(ht, 0, iptr->isn_arg.string, TRUE);
@@ -1839,10 +1653,10 @@ call_def_function(
}
else
{
- if (GA_GROW(&ectx.ec_stack, 1) == FAIL)
- goto failed;
+ if (GA_GROW(&ectx->ec_stack, 1) == FAIL)
+ return FAIL;
copy_tv(&di->di_tv, STACK_TV_BOT(0));
- ++ectx.ec_stack.ga_len;
+ ++ectx->ec_stack.ga_len;
}
}
break;
@@ -1852,13 +1666,13 @@ call_def_function(
{
char_u *name = iptr->isn_arg.string;
- if (GA_GROW(&ectx.ec_stack, 1) == FAIL)
- goto failed;
+ if (GA_GROW(&ectx->ec_stack, 1) == FAIL)
+ return FAIL;
SOURCING_LNUM = iptr->isn_lnum;
if (eval_variable(name, (int)STRLEN(name),
STACK_TV_BOT(0), NULL, EVAL_VAR_VERBOSE) == FAIL)
goto on_error;
- ++ectx.ec_stack.ga_len;
+ ++ectx->ec_stack.ga_len;
}
break;
@@ -1877,16 +1691,16 @@ call_def_function(
case ISN_LOADWDICT: d = curwin->w_vars; break;
case ISN_LOADTDICT: d = curtab->tp_vars; break;
default: // Cannot reach here
- goto failed;
+ return FAIL;
}
- if (GA_GROW(&ectx.ec_stack, 1) == FAIL)
- goto failed;
+ if (GA_GROW(&ectx->ec_stack, 1) == FAIL)
+ return FAIL;
tv = STACK_TV_BOT(0);
tv->v_type = VAR_DICT;
tv->v_lock = 0;
tv->vval.v_dict = d;
++d->dv_refcount;
- ++ectx.ec_stack.ga_len;
+ ++ectx->ec_stack.ga_len;
}
break;
@@ -1898,12 +1712,12 @@ call_def_function(
// This is not expected to fail, name is checked during
// compilation: don't set SOURCING_LNUM.
- if (GA_GROW(&ectx.ec_stack, 1) == FAIL)
- goto failed;
+ if (GA_GROW(&ectx->ec_stack, 1) == FAIL)
+ return FAIL;
if (eval_option(&name, &optval, TRUE) == FAIL)
- goto failed;
+ return FAIL;
*STACK_TV_BOT(0) = optval;
- ++ectx.ec_stack.ga_len;
+ ++ectx->ec_stack.ga_len;
}
break;
@@ -1913,19 +1727,19 @@ call_def_function(
typval_T optval;
char_u *name = iptr->isn_arg.string;
- if (GA_GROW(&ectx.ec_stack, 1) == FAIL)
- goto failed;
+ if (GA_GROW(&ectx->ec_stack, 1) == FAIL)
+ return FAIL;
// name is always valid, checked when compiling
(void)eval_env_var(&name, &optval, TRUE);
*STACK_TV_BOT(0) = optval;
- ++ectx.ec_stack.ga_len;
+ ++ectx->ec_stack.ga_len;
}
break;
// load @register
case ISN_LOADREG:
- if (GA_GROW(&ectx.ec_stack, 1) == FAIL)
- goto failed;
+ if (GA_GROW(&ectx->ec_stack, 1) == FAIL)
+ return FAIL;
tv = STACK_TV_BOT(0);
tv->v_type = VAR_STRING;
tv->v_lock = 0;
@@ -1933,12 +1747,12 @@ call_def_function(
// empty string.
tv->vval.v_string = get_reg_contents(
iptr->isn_arg.number, GREG_EXPR_SRC);
- ++ectx.ec_stack.ga_len;
+ ++ectx->ec_stack.ga_len;
break;
// store local variable
case ISN_STORE:
- --ectx.ec_stack.ga_len;
+ --ectx->ec_stack.ga_len;
tv = STACK_TV_VAR(iptr->isn_arg.number);
clear_tv(tv);
*tv = *STACK_TV_BOT(0);
@@ -1952,7 +1766,7 @@ call_def_function(
char_u *name = iptr->isn_arg.loadstore.ls_name;
dictitem_T *di = find_var_in_ht(ht, 0, name + 2, TRUE);
- --ectx.ec_stack.ga_len;
+ --ectx->ec_stack.ga_len;
if (di == NULL)
store_var(name, STACK_TV_BOT(0));
else
@@ -1975,10 +1789,10 @@ call_def_function(
scriptref_T *sref = iptr->isn_arg.script.scriptref;
svar_T *sv;
- sv = get_script_svar(sref, &ectx);
+ sv = get_script_svar(sref, ectx);
if (sv == NULL)
- goto failed;
- --ectx.ec_stack.ga_len;
+ return FAIL;
+ --ectx->ec_stack.ga_len;
// "const" and "final" are checked at compile time, locking
// the value needs to be checked here.
@@ -2001,7 +1815,7 @@ call_def_function(
char_u *s = NULL;
char *msg;
- --ectx.ec_stack.ga_len;
+ --ectx->ec_stack.ga_len;
tv = STACK_TV_BOT(0);
if (tv->v_type == VAR_STRING)
{
@@ -2026,7 +1840,7 @@ call_def_function(
// store $ENV
case ISN_STOREENV:
- --ectx.ec_stack.ga_len;
+ --ectx->ec_stack.ga_len;
tv = STACK_TV_BOT(0);
vim_setenv_ext(iptr->isn_arg.string, tv_get_string(tv));
clear_tv(tv);
@@ -2037,7 +1851,7 @@ call_def_function(
{
int reg = iptr->isn_arg.number;
- --ectx.ec_stack.ga_len;
+ --ectx->ec_stack.ga_len;
tv = STACK_TV_BOT(0);
write_reg_contents(reg == '@' ? '"' : reg,
tv_get_string(tv), -1, FALSE);
@@ -2047,7 +1861,7 @@ call_def_function(
// store v: variable
case ISN_STOREV:
- --ectx.ec_stack.ga_len;
+ --ectx->ec_stack.ga_len;
if (set_vim_var_tv(iptr->isn_arg.number, STACK_TV_BOT(0))
== FAIL)
// should not happen, type is checked when compiling
@@ -2079,10 +1893,10 @@ call_def_function(
ht = &curtab->tp_vars->dv_hashtab;
break;
default: // Cannot reach here
- goto failed;
+ return FAIL;
}
- --ectx.ec_stack.ga_len;
+ --ectx->ec_stack.ga_len;
di = find_var_in_ht(ht, 0, name, TRUE);
if (di == NULL)
store_var(iptr->isn_arg.string, STACK_TV_BOT(0));
@@ -2102,7 +1916,7 @@ call_def_function(
SOURCING_LNUM = iptr->isn_lnum;
set_var(iptr->isn_arg.string, STACK_TV_BOT(-1), TRUE);
clear_tv(STACK_TV_BOT(-1));
- --ectx.ec_stack.ga_len;
+ --ectx->ec_stack.ga_len;
break;
// store number in local variable
@@ -2184,7 +1998,7 @@ call_def_function(
goto on_error;
// append to list, only fails when out of memory
if (list_append_tv(list, tv) == FAIL)
- goto failed;
+ return FAIL;
clear_tv(tv);
}
}
@@ -2219,7 +2033,7 @@ call_def_function(
goto on_error;
// add to dict, only fails when out of memory
if (dict_add_tv(dict, (char *)key, tv) == FAIL)
- goto failed;
+ return FAIL;
clear_tv(tv);
}
}
@@ -2263,7 +2077,7 @@ call_def_function(
clear_tv(tv_idx);
clear_tv(tv_dest);
- ectx.ec_stack.ga_len -= 3;
+ ectx->ec_stack.ga_len -= 3;
if (status == FAIL)
{
clear_tv(tv);
@@ -2328,7 +2142,7 @@ call_def_function(
clear_tv(tv_idx1);
clear_tv(tv_idx2);
clear_tv(tv_dest);
- ectx.ec_stack.ga_len -= 4;
+ ectx->ec_stack.ga_len -= 4;
clear_tv(tv);
if (status == FAIL)
@@ -2341,7 +2155,7 @@ call_def_function(
case ISN_STOREOUTER:
{
int depth = iptr->isn_arg.outer.outer_depth;
- outer_T *outer = ectx.ec_outer;
+ outer_T *outer = ectx->ec_outer;
while (depth > 1 && outer != NULL)
{
@@ -2352,21 +2166,21 @@ call_def_function(
{
SOURCING_LNUM = iptr->isn_lnum;
iemsg("LOADOUTER depth more than scope levels");
- goto failed;
+ return FAIL;
}
tv = ((typval_T *)outer->out_stack->ga_data)
+ outer->out_frame_idx + STACK_FRAME_SIZE
+ iptr->isn_arg.outer.outer_idx;
if (iptr->isn_type == ISN_LOADOUTER)
{
- if (GA_GROW(&ectx.ec_stack, 1) == FAIL)
- goto failed;
+ if (GA_GROW(&ectx->ec_stack, 1) == FAIL)
+ return FAIL;
copy_tv(tv, STACK_TV_BOT(0));
- ++ectx.ec_stack.ga_len;
+ ++ectx->ec_stack.ga_len;
}
else
{
- --ectx.ec_stack.ga_len;
+ --ectx->ec_stack.ga_len;
clear_tv(tv);
*tv = *STACK_TV_BOT(0);
}
@@ -2453,7 +2267,7 @@ call_def_function(
clear_tv(tv_idx);
clear_tv(tv_dest);
- ectx.ec_stack.ga_len -= 2;
+ ectx->ec_stack.ga_len -= 2;
if (status == FAIL)
goto on_error;
}
@@ -2505,7 +2319,7 @@ call_def_function(
clear_tv(tv_idx1);
clear_tv(tv_idx2);
clear_tv(tv_dest);
- ectx.ec_stack.ga_len -= 3;
+ ectx->ec_stack.ga_len -= 3;
if (status == FAIL)
goto on_error;
}
@@ -2521,11 +2335,11 @@ call_def_function(
case ISN_PUSHFUNC:
case ISN_PUSHCHANNEL:
case ISN_PUSHJOB:
- if (GA_GROW(&ectx.ec_stack, 1) == FAIL)
- goto failed;
+ if (GA_GROW(&ectx->ec_stack, 1) == FAIL)
+ return FAIL;
tv = STACK_TV_BOT(0);
tv->v_lock = 0;
- ++ectx.ec_stack.ga_len;
+ ++ectx->ec_stack.ga_len;
switch (iptr->isn_type)
{
case ISN_PUSHNR:
@@ -2597,8 +2411,8 @@ call_def_function(
// create a list from items on the stack; uses a single allocation
// for the list header and the items
case ISN_NEWLIST:
- if (exe_newlist(iptr->isn_arg.number, &ectx) == FAIL)
- goto failed;
+ if (exe_newlist(iptr->isn_arg.number, ectx) == FAIL)
+ return FAIL;
break;
// create a dict from items on the stack
@@ -2608,9 +2422,10 @@ call_def_function(
dict_T *dict = dict_alloc();
dictitem_T *item;
char_u *key;
+ int idx;
if (dict == NULL)
- goto failed;
+ return FAIL;
for (idx = 0; idx < count; ++idx)
{
// have already checked key type is VAR_STRING
@@ -2631,7 +2446,7 @@ call_def_function(
if (item == NULL)
{
dict_unref(dict);
- goto failed;
+ return FAIL;
}
item->di_tv = *STACK_TV_BOT(2 * (idx - count) + 1);
item->di_tv.v_lock = 0;
@@ -2639,16 +2454,16 @@ call_def_function(
{
// can this ever happen?
dict_unref(dict);
- goto failed;
+ return FAIL;
}
}
if (count > 0)
- ectx.ec_stack.ga_len -= 2 * count - 1;
- else if (GA_GROW(&ectx.ec_stack, 1) == FAIL)
- goto failed;
+ ectx->ec_stack.ga_len -= 2 * count - 1;
+ else if (GA_GROW(&ectx->ec_stack, 1) == FAIL)
+ return FAIL;
else
- ++ectx.ec_stack.ga_len;
+ ++ectx->ec_stack.ga_len;
tv = STACK_TV_BOT(-1);
tv->v_type = VAR_DICT;
tv->v_lock = 0;
@@ -2663,8 +2478,7 @@ call_def_function(
if (call_dfunc(iptr->isn_arg.dfunc.cdf_idx,
NULL,
iptr->isn_arg.dfunc.cdf_argcount,
- &funclocal,
- &ectx) == FAIL)
+ ectx) == FAIL)
goto on_error;
break;
@@ -2673,7 +2487,7 @@ call_def_function(
SOURCING_LNUM = iptr->isn_lnum;
if (call_bfunc(iptr->isn_arg.bfunc.cbf_idx,
iptr->isn_arg.bfunc.cbf_argcount,
- &ectx) == FAIL)
+ ectx) == FAIL)
goto on_error;
break;
@@ -2693,12 +2507,11 @@ call_def_function(
else
{
// Get the funcref from the stack.
- --ectx.ec_stack.ga_len;
+ --ectx->ec_stack.ga_len;
partial_tv = *STACK_TV_BOT(0);
tv = &partial_tv;
}
- r = call_partial(tv, pfunc->cpf_argcount,
- &funclocal, &ectx);
+ r = call_partial(tv, pfunc->cpf_argcount, ectx);
if (tv == &partial_tv)
clear_tv(&partial_tv);
if (r == FAIL)
@@ -2710,7 +2523,7 @@ call_def_function(
// PCALL finished, arguments have been consumed and replaced by
// the return value. Now clear the funcref from the stack,
// and move the return value in its place.
- --ectx.ec_stack.ga_len;
+ --ectx->ec_stack.ga_len;
clear_tv(STACK_TV_BOT(-1));
*STACK_TV_BOT(-1) = *STACK_TV_BOT(0);
break;
@@ -2722,17 +2535,17 @@ call_def_function(
SOURCING_LNUM = iptr->isn_lnum;
if (call_eval_func(cufunc->cuf_name, cufunc->cuf_argcount,
- &funclocal, &ectx, iptr) == FAIL)
+ ectx, iptr) == FAIL)
goto on_error;
}
break;
// return from a :def function call
case ISN_RETURN_ZERO:
- if (GA_GROW(&ectx.ec_stack, 1) == FAIL)
- goto failed;
+ if (GA_GROW(&ectx->ec_stack, 1) == FAIL)
+ return FAIL;
tv = STACK_TV_BOT(0);
- ++ectx.ec_stack.ga_len;
+ ++ectx->ec_stack.ga_len;
tv->v_type = VAR_NUMBER;
tv->vval.v_number = 0;
tv->v_lock = 0;
@@ -2740,20 +2553,20 @@ call_def_function(
case ISN_RETURN:
{
- garray_T *trystack = &ectx.ec_trystack;
+ garray_T *trystack = &ectx->ec_trystack;
trycmd_T *trycmd = NULL;
if (trystack->ga_len > 0)
trycmd = ((trycmd_T *)trystack->ga_data)
+ trystack->ga_len - 1;
if (trycmd != NULL
- && trycmd->tcd_frame_idx == ectx.ec_frame_idx)
+ && trycmd->tcd_frame_idx == ectx->ec_frame_idx)
{
// jump to ":finally" or ":endtry"
if (trycmd->tcd_finally_idx != 0)
- ectx.ec_iidx = trycmd->tcd_finally_idx;
+ ectx->ec_iidx = trycmd->tcd_finally_idx;
else
- ectx.ec_iidx = trycmd->tcd_endtry_idx;
+ ectx->ec_iidx = trycmd->tcd_endtry_idx;
trycmd->tcd_return = TRUE;
}
else
@@ -2769,18 +2582,18 @@ call_def_function(
+ iptr->isn_arg.funcref.fr_func;
if (pt == NULL)
- goto failed;
- if (GA_GROW(&ectx.ec_stack, 1) == FAIL)
+ return FAIL;
+ if (GA_GROW(&ectx->ec_stack, 1) == FAIL)
{
vim_free(pt);
- goto failed;
+ return FAIL;
}
if (fill_partial_and_closure(pt, pt_dfunc->df_ufunc,
- &ectx) == FAIL)
- goto failed;
+ ectx) == FAIL)
+ return FAIL;
tv = STACK_TV_BOT(0);
- ++ectx.ec_stack.ga_len;
+ ++ectx->ec_stack.ga_len;
tv->vval.v_partial = pt;
tv->v_type = VAR_PARTIAL;
tv->v_lock = 0;
@@ -2793,8 +2606,8 @@ call_def_function(
newfunc_T *newfunc = &iptr->isn_arg.newfunc;
if (copy_func(newfunc->nf_lambda, newfunc->nf_global,
- &ectx) == FAIL)
- goto failed;
+ ectx) == FAIL)
+ return FAIL;
}
break;
@@ -2841,11 +2654,11 @@ call_def_function(
{
// drop the value from the stack
clear_tv(tv);
- --ectx.ec_stack.ga_len;
+ --ectx->ec_stack.ga_len;
}
}
if (jump)
- ectx.ec_iidx = iptr->isn_arg.jump.jump_where;
+ ectx->ec_iidx = iptr->isn_arg.jump.jump_where;
}
break;
@@ -2856,7 +2669,7 @@ call_def_function(
if (tv->v_type != VAR_UNKNOWN
&& !(tv->v_type == VAR_SPECIAL
&& tv->vval.v_number == VVAL_NONE))
- ectx.ec_iidx = iptr->isn_arg.jumparg.jump_where;
+ ectx->ec_iidx = iptr->isn_arg.jumparg.jump_where;
break;
// top of a for loop
@@ -2866,8 +2679,8 @@ call_def_function(
typval_T *idxtv =
STACK_TV_VAR(iptr->isn_arg.forloop.for_idx);
- if (GA_GROW(&ectx.ec_stack, 1) == FAIL)
- goto failed;
+ if (GA_GROW(&ectx->ec_stack, 1) == FAIL)
+ return FAIL;
if (ltv->v_type == VAR_LIST)
{
list_T *list = ltv->vval.v_list;
@@ -2878,8 +2691,8 @@ call_def_function(
|| idxtv->vval.v_number >= list->lv_len)
{
// past the end of the list, jump to "endfor"
- ectx.ec_iidx = iptr->isn_arg.forloop.for_end;
- may_restore_cmdmod(&funclocal);
+ ectx->ec_iidx = iptr->isn_arg.forloop.for_end;
+ may_restore_cmdmod(&ectx->ec_funclocal);
}
else if (list->lv_first == &range_list_item)
{
@@ -2889,7 +2702,7 @@ call_def_function(
tv->v_lock = 0;
tv->vval.v_number = list_find_nr(
list, idxtv->vval.v_number, NULL);
- ++ectx.ec_stack.ga_len;
+ ++ectx->ec_stack.ga_len;
}
else
{
@@ -2897,7 +2710,7 @@ call_def_function(
idxtv->vval.v_number);
copy_tv(&li->li_tv, STACK_TV_BOT(0));
- ++ectx.ec_stack.ga_len;
+ ++ectx->ec_stack.ga_len;
}
}
else if (ltv->v_type == VAR_STRING)
@@ -2910,8 +2723,8 @@ call_def_function(
if (str == NULL || str[idxtv->vval.v_number] == NUL)
{
// past the end of the string, jump to "endfor"
- ectx.ec_iidx = iptr->isn_arg.forloop.for_end;
- may_restore_cmdmod(&funclocal);
+ ectx->ec_iidx = iptr->isn_arg.forloop.for_end;
+ may_restore_cmdmod(&ectx->ec_funclocal);
}
else
{
@@ -2922,7 +2735,7 @@ call_def_function(
tv->v_type = VAR_STRING;
tv->vval.v_string = vim_strnsave(
str + idxtv->vval.v_number, clen);
- ++ectx.ec_stack.ga_len;
+ ++ectx->ec_stack.ga_len;
idxtv->vval.v_number += clen - 1;
}
}
@@ -2946,8 +2759,8 @@ call_def_function(
|| idxtv->vval.v_number >= blob_len(blob))
{
// past the end of the blob, jump to "endfor"
- ectx.ec_iidx = iptr->isn_arg.forloop.for_end;
- may_restore_cmdmod(&funclocal);
+ ectx->ec_iidx = iptr->isn_arg.forloop.for_end;
+ may_restore_cmdmod(&ectx->ec_funclocal);
}
else
{
@@ -2956,14 +2769,14 @@ call_def_function(
tv->v_type = VAR_NUMBER;
tv->vval.v_number = blob_get(blob,
idxtv->vval.v_number);
- ++ectx.ec_stack.ga_len;
+ ++ectx->ec_stack.ga_len;
}
}
else
{
semsg(_(e_for_loop_on_str_not_supported),
vartype_name(ltv->v_type));
- goto failed;
+ return FAIL;
}
}
break;
@@ -2973,15 +2786,15 @@ call_def_function(
{
trycmd_T *trycmd = NULL;
- if (GA_GROW(&ectx.ec_trystack, 1) == FAIL)
- goto failed;
- trycmd = ((trycmd_T *)ectx.ec_trystack.ga_data)
- + ectx.ec_trystack.ga_len;
- ++ectx.ec_trystack.ga_len;
+ if (GA_GROW(&ectx->ec_trystack, 1) == FAIL)
+ return FAIL;
+ trycmd = ((trycmd_T *)ectx->ec_trystack.ga_data)
+ + ectx->ec_trystack.ga_len;
+ ++ectx->ec_trystack.ga_len;
++trylevel;
CLEAR_POINTER(trycmd);
- trycmd->tcd_frame_idx = ectx.ec_frame_idx;
- trycmd->tcd_stack_len = ectx.ec_stack.ga_len;
+ trycmd->tcd_frame_idx = ectx->ec_frame_idx;
+ trycmd->tcd_stack_len = ectx->ec_stack.ga_len;
trycmd->tcd_catch_idx =
iptr->isn_arg.try.try_ref->try_catch;
trycmd->tcd_finally_idx =
@@ -2996,12 +2809,12 @@ call_def_function(
{
SOURCING_LNUM = iptr->isn_lnum;
iemsg("Evaluating catch while current_exception is NULL");
- goto failed;
+ return FAIL;
}
- if (GA_GROW(&ectx.ec_stack, 1) == FAIL)
- goto failed;
+ if (GA_GROW(&ectx->ec_stack, 1) == FAIL)
+ return FAIL;
tv = STACK_TV_BOT(0);
- ++ectx.ec_stack.ga_len;
+ ++ectx->ec_stack.ga_len;
tv->v_type = VAR_STRING;
tv->v_lock = 0;
tv->vval.v_string = vim_strsave(
@@ -3010,9 +2823,9 @@ call_def_function(
case ISN_CATCH:
{
- garray_T *trystack = &ectx.ec_trystack;
+ garray_T *trystack = &ectx->ec_trystack;
- may_restore_cmdmod(&funclocal);
+ may_restore_cmdmod(&ectx->ec_funclocal);
if (trystack->ga_len > 0)
{
trycmd_T *trycmd = ((trycmd_T *)trystack->ga_data)
@@ -3027,7 +2840,7 @@ call_def_function(
case ISN_TRYCONT:
{
- garray_T *trystack = &ectx.ec_trystack;
+ garray_T *trystack = &ectx->ec_trystack;
trycont_T *trycont = &iptr->isn_arg.trycont;
int i;
trycmd_T *trycmd;
@@ -3037,7 +2850,7 @@ call_def_function(
{
siemsg("TRYCONT: expected %d levels, found %d",
trycont->tct_levels, trystack->ga_len);
- goto failed;
+ return FAIL;
}
// Make :endtry jump to any outer try block and the last
// :endtry inside the loop to the loop start.
@@ -3052,13 +2865,13 @@ call_def_function(
? trycmd->tcd_endtry_idx : trycmd->tcd_finally_idx;
}
// jump to :finally or :endtry of current try statement
- ectx.ec_iidx = iidx;
+ ectx->ec_iidx = iidx;
}
break;
case ISN_FINALLY:
{
- garray_T *trystack = &ectx.ec_trystack;
+ garray_T *trystack = &ectx->ec_trystack;
trycmd_T *trycmd = ((trycmd_T *)trystack->ga_data)
+ trystack->ga_len - 1;
@@ -3071,7 +2884,7 @@ call_def_function(
// end of ":try" block
case ISN_ENDTRY:
{
- garray_T *trystack = &ectx.ec_trystack;
+ garray_T *trystack = &ectx->ec_trystack;
if (trystack->ga_len > 0)
{
@@ -3079,7 +2892,7 @@ call_def_function(
--trystack->ga_len;
--trylevel;
- ectx.ec_in_catch = FALSE;
+ ectx->ec_in_catch = FALSE;
trycmd = ((trycmd_T *)trystack->ga_data)
+ trystack->ga_len;
if (trycmd->tcd_caught && current_exception != NULL)
@@ -3093,22 +2906,22 @@ call_def_function(
if (trycmd->tcd_return)
goto func_return;
- while (ectx.ec_stack.ga_len > trycmd->tcd_stack_len)
+ while (ectx->ec_stack.ga_len > trycmd->tcd_stack_len)
{
- --ectx.ec_stack.ga_len;
+ --ectx->ec_stack.ga_len;
clear_tv(STACK_TV_BOT(0));
}
if (trycmd->tcd_cont != 0)
// handling :continue: jump to outer try block or
// start of the loop
- ectx.ec_iidx = trycmd->tcd_cont - 1;
+ ectx->ec_iidx = trycmd->tcd_cont - 1;
}
}
break;
case ISN_THROW:
{
- garray_T *trystack = &ectx.ec_trystack;
+ garray_T *trystack = &ectx->ec_trystack;
if (trystack->ga_len == 0 && trylevel == 0 && emsg_silent)
{
@@ -3120,7 +2933,7 @@ call_def_function(
tv->vval.v_number = 0;
goto done;
}
- --ectx.ec_stack.ga_len;
+ --ectx->ec_stack.ga_len;
tv = STACK_TV_BOT(0);
if (tv->vval.v_string == NULL
|| *skipwhite(tv->vval.v_string) == NUL)
@@ -3128,7 +2941,7 @@ call_def_function(
vim_free(tv->vval.v_string);
SOURCING_LNUM = iptr->isn_lnum;
emsg(_(e_throw_with_empty_string));
- goto failed;
+ return FAIL;
}
// Inside a "catch" we need to first discard the caught
@@ -3151,7 +2964,7 @@ call_def_function(
== FAIL)
{
vim_free(tv->vval.v_string);
- goto failed;
+ return FAIL;
}
did_throw = TRUE;
}
@@ -3174,7 +2987,7 @@ call_def_function(
default: res = 0; break;
}
- --ectx.ec_stack.ga_len;
+ --ectx->ec_stack.ga_len;
tv1->v_type = VAR_BOOL;
tv1->vval.v_number = res ? VVAL_TRUE : VVAL_FALSE;
}
@@ -3207,7 +3020,7 @@ call_def_function(
default: res = 0; break;
}
- --ectx.ec_stack.ga_len;
+ --ectx->ec_stack.ga_len;
if (iptr->isn_type == ISN_COMPARENR)
{
tv1->v_type = VAR_BOOL;
@@ -3245,7 +3058,7 @@ call_def_function(
case EXPR_SEQUAL: cmp = arg1 <= arg2; break;
default: cmp = 0; break;
}
- --ectx.ec_stack.ga_len;
+ --ectx->ec_stack.ga_len;
if (iptr->isn_type == ISN_COMPAREFLOAT)
{
tv1->v_type = VAR_BOOL;
@@ -3276,7 +3089,7 @@ call_def_function(
case EXPR_ISNOT: cmp = arg1 != arg2; break;
default: cmp = 0; break;
}
- --ectx.ec_stack.ga_len;
+ --ectx->ec_stack.ga_len;
clear_tv(tv1);
clear_tv(tv2);
tv1->v_type = VAR_BOOL;
@@ -3300,7 +3113,7 @@ call_def_function(
case EXPR_ISNOT: cmp = arg1 != arg2; break;
default: cmp = 0; break;
}
- --ectx.ec_stack.ga_len;
+ --ectx->ec_stack.ga_len;
clear_tv(tv1);
clear_tv(tv2);
tv1->v_type = VAR_BOOL;
@@ -3322,7 +3135,7 @@ call_def_function(
SOURCING_LNUM = iptr->isn_lnum;
typval_compare(tv1, tv2, exprtype, ic);
clear_tv(tv2);
- --ectx.ec_stack.ga_len;
+ --ectx->ec_stack.ga_len;
}
break;
@@ -3338,7 +3151,7 @@ call_def_function(
else
eval_addblob(tv1, tv2);
clear_tv(tv2);
- --ectx.ec_stack.ga_len;
+ --ectx->ec_stack.ga_len;
}
break;
@@ -3356,9 +3169,9 @@ call_def_function(
goto on_error;
}
if (list_append_tv(l, tv2) == FAIL)
- goto failed;
+ return FAIL;
clear_tv(tv2);
- --ectx.ec_stack.ga_len;
+ --ectx->ec_stack.ga_len;
}
break;
@@ -3381,7 +3194,7 @@ call_def_function(
if (error)
goto on_error;
ga_append(&b->bv_ga, (int)n);
- --ectx.ec_stack.ga_len;
+ --ectx->ec_stack.ga_len;
}
break;
@@ -3402,7 +3215,7 @@ call_def_function(
{
eval_addlist(tv1, tv2);
clear_tv(tv2);
- --ectx.ec_stack.ga_len;
+ --ectx->ec_stack.ga_len;
break;
}
else if (tv1->v_type == VAR_BLOB
@@ -3410,7 +3223,7 @@ call_def_function(
{
eval_addblob(tv1, tv2);
clear_tv(tv2);
- --ectx.ec_stack.ga_len;
+ --ectx->ec_stack.ga_len;
break;
}
}
@@ -3467,7 +3280,7 @@ call_def_function(
clear_tv(tv2);
tv1->v_type = VAR_FLOAT;
tv1->vval.v_float = f1;
- --ectx.ec_stack.ga_len;
+ --ectx->ec_stack.ga_len;
}
else
#endif
@@ -3492,7 +3305,7 @@ call_def_function(
clear_tv(tv2);
tv1->v_type = VAR_NUMBER;
tv1->vval.v_number = n1;
- --ectx.ec_stack.ga_len;
+ --ectx->ec_stack.ga_len;
}
}
break;
@@ -3506,7 +3319,7 @@ call_def_function(
res = concat_str(str1, str2);
clear_tv(STACK_TV_BOT(-2));
clear_tv(STACK_TV_BOT(-1));
- --ectx.ec_stack.ga_len;
+ --ectx->ec_stack.ga_len;
STACK_TV_BOT(-1)->vval.v_string = res;
}
break;
@@ -3530,7 +3343,7 @@ call_def_function(
tv = STACK_TV_BOT(-1);
n2 = tv->vval.v_number;
- ectx.ec_stack.ga_len -= is_slice ? 2 : 1;
+ ectx->ec_stack.ga_len -= is_slice ? 2 : 1;
tv = STACK_TV_BOT(-1);
if (is_slice)
// Slice: Select the characters from the string
@@ -3575,7 +3388,7 @@ call_def_function(
clear_tv(tv);
}
- ectx.ec_stack.ga_len -= is_slice ? 2 : 1;
+ ectx->ec_stack.ga_len -= is_slice ? 2 : 1;
tv = STACK_TV_BOT(-1);
SOURCING_LNUM = iptr->isn_lnum;
if (is_blob)
@@ -3614,7 +3427,7 @@ call_def_function(
clear_tv(var1);
if (is_slice)
clear_tv(var2);
- ectx.ec_stack.ga_len -= is_slice ? 2 : 1;
+ ectx->ec_stack.ga_len -= is_slice ? 2 : 1;
if (res == FAIL)
goto on_error;
}
@@ -3655,15 +3468,15 @@ call_def_function(
tv = STACK_TV_BOT(-1);
li = list_find(tv->vval.v_list, index);
- if (GA_GROW(&ectx.ec_stack, 1) == FAIL)
- goto failed;
- ++ectx.ec_stack.ga_len;
+ if (GA_GROW(&ectx->ec_stack, 1) == FAIL)
+ return FAIL;
+ ++ectx->ec_stack.ga_len;
copy_tv(&li->li_tv, STACK_TV_BOT(-1));
// Useful when used in unpack assignment. Reset at
// ISN_DROP.
- where.wt_index = index + 1;
- where.wt_variable = TRUE;
+ ectx->ec_where.wt_index = index + 1;
+ ectx->ec_where.wt_variable = TRUE;
}
break;
@@ -3693,7 +3506,7 @@ call_def_function(
// If :silent! is used we will continue, make sure the
// stack contents makes sense.
clear_tv(tv);
- --ectx.ec_stack.ga_len;
+ --ectx->ec_stack.ga_len;
tv = STACK_TV_BOT(-1);
clear_tv(tv);
tv->v_type = VAR_NUMBER;
@@ -3701,7 +3514,7 @@ call_def_function(
goto on_fatal_error;
}
clear_tv(tv);
- --ectx.ec_stack.ga_len;
+ --ectx->ec_stack.ga_len;
// Clear the dict only after getting the item, to avoid
// that it makes the item invalid.
tv = STACK_TV_BOT(-1);
@@ -3782,12 +3595,13 @@ call_def_function(
tv = STACK_TV_BOT((int)ct->ct_off);
SOURCING_LNUM = iptr->isn_lnum;
- if (!where.wt_variable)
- where.wt_index = ct->ct_arg_idx;
- if (check_typval_type(ct->ct_type, tv, where) == FAIL)
+ if (!ectx->ec_where.wt_variable)
+ ectx->ec_where.wt_index = ct->ct_arg_idx;
+ if (check_typval_type(ct->ct_type, tv, ectx->ec_where)
+ == FAIL)
goto on_error;
- if (!where.wt_variable)
- where.wt_index = 0;
+ if (!ectx->ec_where.wt_variable)
+ ectx->ec_where.wt_index = 0;
// number 0 is FALSE, number 1 is TRUE
if (tv->v_type == VAR_NUMBER
@@ -3887,9 +3701,9 @@ call_def_function(
if (parse_cmd_address(&ea, &errormsg, FALSE) == FAIL)
goto on_error;
- if (GA_GROW(&ectx.ec_stack, 1) == FAIL)
- goto failed;
- ++ectx.ec_stack.ga_len;
+ if (GA_GROW(&ectx->ec_stack, 1) == FAIL)
+ return FAIL;
+ ++ectx->ec_stack.ga_len;
tv = STACK_TV_BOT(-1);
tv->v_type = VAR_NUMBER;
tv->v_lock = 0;
@@ -3914,7 +3728,7 @@ call_def_function(
curwin->w_cursor.lnum = tv->vval.v_number;
if (lnum == LNUM_VARIABLE_RANGE_ABOVE)
dir = BACKWARD;
- --ectx.ec_stack.ga_len;
+ --ectx->ec_stack.ga_len;
}
else if (lnum == -2)
// :put! above cursor
@@ -3932,7 +3746,7 @@ call_def_function(
expr = typval2string(tv, TRUE); // allocates value
clear_tv(tv);
}
- --ectx.ec_stack.ga_len;
+ --ectx->ec_stack.ga_len;
}
check_cursor();
do_put(regname, expr, dir, 1L, PUT_LINE|PUT_CURSLINE);
@@ -3941,9 +3755,10 @@ call_def_function(
break;
case ISN_CMDMOD:
- funclocal.floc_save_cmdmod = cmdmod;
- funclocal.floc_restore_cmdmod = TRUE;
- funclocal.floc_restore_cmdmod_stacklen = ectx.ec_stack.ga_len;
+ ectx->ec_funclocal.floc_save_cmdmod = cmdmod;
+ ectx->ec_funclocal.floc_restore_cmdmod = TRUE;
+ ectx->ec_funclocal.floc_restore_cmdmod_stacklen =
+ ectx->ec_stack.ga_len;
cmdmod = *iptr->isn_arg.cmdmod.cf_cmdmod;
apply_cmdmod(&cmdmod);
break;
@@ -3952,8 +3767,8 @@ call_def_function(
// filter regprog is owned by the instruction, don't free it
cmdmod.cmod_filter_regmatch.regprog = NULL;
undo_cmdmod(&cmdmod);
- cmdmod = funclocal.floc_save_cmdmod;
- funclocal.floc_restore_cmdmod = FALSE;
+ cmdmod = ectx->ec_funclocal.floc_save_cmdmod;
+ ectx->ec_funclocal.floc_restore_cmdmod = FALSE;
break;
case ISN_UNPACK:
@@ -3988,9 +3803,9 @@ call_def_function(
}
CHECK_LIST_MATERIALIZE(l);
- if (GA_GROW(&ectx.ec_stack, count - 1) == FAIL)
- goto failed;
- ectx.ec_stack.ga_len += count - 1;
+ if (GA_GROW(&ectx->ec_stack, count - 1) == FAIL)
+ return FAIL;
+ ectx->ec_stack.ga_len += count - 1;
// Variable after semicolon gets a list with the remaining
// items.
@@ -4000,7 +3815,7 @@ call_def_function(
list_alloc_with_items(l->lv_len - count + 1);
if (rem_list == NULL)
- goto failed;
+ return FAIL;
tv = STACK_TV_BOT(-count);
tv->vval.v_list = rem_list;
++rem_list->lv_refcount;
@@ -4036,7 +3851,7 @@ call_def_function(
funccall_T cookie;
ufunc_T *cur_ufunc =
(((dfunc_T *)def_functions.ga_data)
- + ectx.ec_dfunc_idx)->df_ufunc;
+ + ectx->ec_dfunc_idx)->df_ufunc;
cookie.func = cur_ufunc;
if (iptr->isn_type == ISN_PROF_START)
@@ -4068,10 +3883,10 @@ call_def_function(
break;
case ISN_DROP:
- --ectx.ec_stack.ga_len;
+ --ectx->ec_stack.ga_len;
clear_tv(STACK_TV_BOT(0));
- where.wt_index = 0;
- where.wt_variable = FALSE;
+ ectx->ec_where.wt_index = 0;
+ ectx->ec_where.wt_variable = FALSE;
break;
}
continue;
@@ -4079,62 +3894,345 @@ call_def_function(
func_return:
// Restore previous function. If the frame pointer is where we started
// then there is none and we are done.
- if (ectx.ec_frame_idx == initial_frame_idx)
+ if (ectx->ec_frame_idx == ectx->ec_initial_frame_idx)
goto done;
- if (func_return(&funclocal, &ectx) == FAIL)
+ if (func_return(ectx) == FAIL)
// only fails when out of memory
- goto failed;
+ return FAIL;
continue;
on_error:
// Jump here for an error that does not require aborting execution.
// If "emsg_silent" is set then ignore the error, unless it was set
// when calling the function.
- if (did_emsg_cumul + did_emsg == did_emsg_before
+ if (did_emsg_cumul + did_emsg == ectx->ec_did_emsg_before
&& emsg_silent && did_emsg_def == 0)
{
// If a sequence of instructions causes an error while ":silent!"
// was used, restore the stack length and jump ahead to restoring
// the cmdmod.
- if (funclocal.floc_restore_cmdmod)
+ if (ectx->ec_funclocal.floc_restore_cmdmod)
{
- while (ectx.ec_stack.ga_len
- > funclocal.floc_restore_cmdmod_stacklen)
+ while (ectx->ec_stack.ga_len
+ > ectx->ec_funclocal.floc_restore_cmdmod_stacklen)
{
- --ectx.ec_stack.ga_len;
+ --ectx->ec_stack.ga_len;
clear_tv(STACK_TV_BOT(0));
}
- while (ectx.ec_instr[ectx.ec_iidx].isn_type != ISN_CMDMOD_REV)
- ++ectx.ec_iidx;
+ while (ectx->ec_instr[ectx->ec_iidx].isn_type != ISN_CMDMOD_REV)
+ ++ectx->ec_iidx;
}
continue;
}
on_fatal_error:
// Jump here for an error that messes up the stack.
// If we are not inside a try-catch started here, abort execution.
- if (trylevel <= trylevel_at_start)
- goto failed;
+ if (trylevel <= ectx->ec_trylevel_at_start)
+ return FAIL;
}
done:
- // function finished, get result from the stack.
- if (ufunc->uf_ret_type == &t_void)
+ return OK;
+}
+
+/*
+ * Execute the instructions from an ISN_SUBSTITUTE command, which are in
+ * "substitute_instr".
+ */
+ char_u *
+exe_substitute_instr(void)
+{
+ ectx_T *ectx = substitute_instr->subs_ectx;
+ isn_T *save_instr = ectx->ec_instr;
+ int save_iidx = ectx->ec_iidx;
+ char_u *res;
+
+ ectx->ec_instr = substitute_instr->subs_instr;
+ if (exec_instructions(ectx) == OK)
{
- rettv->v_type = VAR_VOID;
+ typval_T *tv = STACK_TV_BOT(-1);
+
+ res = vim_strsave(tv_get_string(tv));
+ --ectx->ec_stack.ga_len;
+ clear_tv(tv);
}
else
{
+ substitute_instr->subs_status = FAIL;
+ res = vim_strsave((char_u *)"");
+ }
+
+ ectx->ec_instr = save_instr;
+ ectx->ec_iidx = save_iidx;
+
+ return res;
+}
+
+/*
+ * Call a "def" function from old Vim script.
+ * Return OK or FAIL.
+ */
+ int
+call_def_function(
+ ufunc_T *ufunc,
+ int argc_arg, // nr of arguments
+ typval_T *argv, // arguments
+ partial_T *partial, // optional partial for context
+ typval_T *rettv) // return value
+{
+ ectx_T ectx; // execution context
+ int argc = argc_arg;
+ typval_T *tv;
+ int idx;
+ int ret = FAIL;
+ int defcount = ufunc->uf_args.ga_len - argc;
+ sctx_T save_current_sctx = current_sctx;
+ int did_emsg_before = did_emsg_cumul + did_emsg;
+ int save_suppress_errthrow = suppress_errthrow;
+ msglist_T **saved_msg_list = NULL;
+ msglist_T *private_msg_list = NULL;
+ int save_emsg_silent_def = emsg_silent_def;
+ int save_did_emsg_def = did_emsg_def;
+ int orig_funcdepth;
+
+// Get pointer to item in the stack.
+#undef STACK_TV
+#define STACK_TV(idx) (((typval_T *)ectx.ec_stack.ga_data) + idx)
+
+// Get pointer to item at the bottom of the stack, -1 is the bottom.
+#undef STACK_TV_BOT
+#define STACK_TV_BOT(idx) (((typval_T *)ectx.ec_stack.ga_data) + ectx.ec_stack.ga_len + idx)
+
+// Get pointer to a local variable on the stack. Negative for arguments.
+#undef STACK_TV_VAR
+#define STACK_TV_VAR(idx) (((typval_T *)ectx.ec_stack.ga_data) + ectx.ec_frame_idx + STACK_FRAME_SIZE + idx)
+
+ if (ufunc->uf_def_status == UF_NOT_COMPILED
+ || ufunc->uf_def_status == UF_COMPILE_ERROR
+ || (func_needs_compiling(ufunc, PROFILING(ufunc))
+ && compile_def_function(ufunc, FALSE, PROFILING(ufunc), NULL)
+ == FAIL))
+ {
+ if (did_emsg_cumul + did_emsg == did_emsg_before)
+ semsg(_(e_function_is_not_compiled_str),
+ printable_func_name(ufunc));
+ return FAIL;
+ }
+
+ {
+ // Check the function was really compiled.
+ dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data)
+ + ufunc->uf_dfunc_idx;
+ if (INSTRUCTIONS(dfunc) == NULL)
+ {
+ iemsg("using call_def_function() on not compiled function");
+ return FAIL;
+ }
+ }
+
+ // If depth of calling is getting too high, don't execute the function.
+ orig_funcdepth = funcdepth_get();
+ if (funcdepth_increment() == FAIL)
+ return FAIL;
+
+ CLEAR_FIELD(ectx);
+ ectx.ec_dfunc_idx = ufunc->uf_dfunc_idx;
+ ga_init2(&ectx.ec_stack, sizeof(typval_T), 500);
+ if (ga_grow(&ectx.ec_stack, 20) == FAIL)
+ {
+ funcdepth_decrement();
+ return FAIL;
+ }
+ ga_init2(&ectx.ec_trystack, sizeof(trycmd_T), 10);
+ ga_init2(&ectx.ec_funcrefs, sizeof(partial_T *), 10);
+ ectx.ec_did_emsg_before = did_emsg_before;
+ ectx.ec_trylevel_at_start = trylevel;
+
+ idx = argc - ufunc->uf_args.ga_len;
+ if (idx > 0 && ufunc->uf_va_name == NULL)
+ {
+ if (idx == 1)
+ emsg(_(e_one_argument_too_many));
+ else
+ semsg(_(e_nr_arguments_too_many), idx);
+ goto failed_early;
+ }
+
+ // Put arguments on the stack, but no more than what the function expects.
+ // A lambda can be called with more arguments than it uses.
+ for (idx = 0; idx < argc
+ && (ufunc->uf_va_name != NULL || idx < ufunc->uf_args.ga_len);
+ ++idx)
+ {
+ if (idx >= ufunc->uf_args.ga_len - ufunc->uf_def_args.ga_len
+ && argv[idx].v_type == VAR_SPECIAL
+ && argv[idx].vval.v_number == VVAL_NONE)
+ {
+ // Use the default value.
+ STACK_TV_BOT(0)->v_type = VAR_UNKNOWN;
+ }
+ else
+ {
+ if (ufunc->uf_arg_types != NULL && idx < ufunc->uf_args.ga_len
+ && check_typval_arg_type(
+ ufunc->uf_arg_types[idx], &argv[idx], idx + 1) == FAIL)
+ goto failed_early;
+ copy_tv(&argv[idx], STACK_TV_BOT(0));
+ }
+ ++ectx.ec_stack.ga_len;
+ }
+
+ // Turn varargs into a list. Empty list if no args.
+ if (ufunc->uf_va_name != NULL)
+ {
+ int vararg_count = argc - ufunc->uf_args.ga_len;
+
+ if (vararg_count < 0)
+ vararg_count = 0;
+ else
+ argc -= vararg_count;
+ if (exe_newlist(vararg_count, &ectx) == FAIL)
+ goto failed_early;
+
+ // Check the type of the list items.
tv = STACK_TV_BOT(-1);
- *rettv = *tv;
- tv->v_type = VAR_UNKNOWN;
+ if (ufunc->uf_va_type != NULL
+ && ufunc->uf_va_type != &t_list_any
+ && ufunc->uf_va_type->tt_member != &t_any
+ && tv->vval.v_list != NULL)
+ {
+ type_T *expected = ufunc->uf_va_type->tt_member;
+ listitem_T *li = tv->vval.v_list->lv_first;
+
+ for (idx = 0; idx < vararg_count; ++idx)
+ {
+ if (check_typval_arg_type(expected, &li->li_tv,
+ argc + idx + 1) == FAIL)
+ goto failed_early;
+ li = li->li_next;
+ }
+ }
+
+ if (defcount > 0)
+ // Move varargs list to below missing default arguments.
+ *STACK_TV_BOT(defcount - 1) = *STACK_TV_BOT(-1);
+ --ectx.ec_stack.ga_len;
+ }
+
+ // Make space for omitted arguments, will store default value below.
+ // Any varargs list goes after them.
+ if (defcount > 0)
+ for (idx = 0; idx < defcount; ++idx)
+ {
+ STACK_TV_BOT(0)->v_type = VAR_UNKNOWN;
+ ++ectx.ec_stack.ga_len;
+ }
+ if (ufunc->uf_va_name != NULL)
+ ++ectx.ec_stack.ga_len;
+
+ // Frame pointer points to just after arguments.
+ ectx.ec_frame_idx = ectx.ec_stack.ga_len;
+ ectx.ec_initial_frame_idx = ectx.ec_frame_idx;
+
+ {
+ dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data)
+ + ufunc->uf_dfunc_idx;
+ ufunc_T *base_ufunc = dfunc->df_ufunc;
+
+ // "uf_partial" is on the ufunc that "df_ufunc" points to, as is done
+ // by copy_func().
+ if (partial != NULL || base_ufunc->uf_partial != NULL)
+ {
+ ectx.ec_outer = ALLOC_CLEAR_ONE(outer_T);
+ if (ectx.ec_outer == NULL)
+ goto failed_early;
+ if (partial != NULL)
+ {
+ if (partial->pt_outer.out_stack == NULL && current_ectx != NULL)
+ {
+ if (current_ectx->ec_outer != NULL)
+ *ectx.ec_outer = *current_ectx->ec_outer;
+ }
+ else
+ *ectx.ec_outer = partial->pt_outer;
+ }
+ else
+ *ectx.ec_outer = base_ufunc->uf_partial->pt_outer;
+ ectx.ec_outer->out_up_is_copy = TRUE;
+ }
+ }
+
+ // dummy frame entries
+ for (idx = 0; idx < STACK_FRAME_SIZE; ++idx)
+ {
+ STACK_TV(ectx.ec_stack.ga_len)->v_type = VAR_UNKNOWN;
+ ++ectx.ec_stack.ga_len;
+ }
+
+ {
+ // Reserve space for local variables and any closure reference count.
+ dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data)
+ + ufunc->uf_dfunc_idx;
+
+ for (idx = 0; idx < dfunc->df_varcount; ++idx)
+ STACK_TV_VAR(idx)->v_type = VAR_UNKNOWN;
+ ectx.ec_stack.ga_len += dfunc->df_varcount;
+ if (dfunc->df_has_closure)
+ {
+ STACK_TV_VAR(idx)->v_type = VAR_NUMBER;
+ STACK_TV_VAR(idx)->vval.v_number = 0;
+ ++ectx.ec_stack.ga_len;
+ }
+
+ ectx.ec_instr = INSTRUCTIONS(dfunc);
+ }
+
+ // Following errors are in the function, not the caller.
+ // Commands behave like vim9script.
+ estack_push_ufunc(ufunc, 1);
+ current_sctx = ufunc->uf_script_ctx;
+ current_sctx.sc_version = SCRIPT_VERSION_VIM9;
+
+ // Use a specific location for storing error messages to be converted to an
+ // exception.
+ saved_msg_list = msg_list;
+ msg_list = &private_msg_list;
+
+ // Do turn errors into exceptions.
+ suppress_errthrow = FALSE;
+
+ // Do not delete the function while executing it.
+ ++ufunc->uf_calls;
+
+ // When ":silent!" was used before calling then we still abort the
+ // function. If ":silent!" is used in the function then we don't.
+ emsg_silent_def = emsg_silent;
+ did_emsg_def = 0;
+
+ ectx.ec_where.wt_index = 0;
+ ectx.ec_where.wt_variable = FALSE;
+
+ // Execute the instructions until done.
+ ret = exec_instructions(&ectx);
+ if (ret == OK)
+ {
+ // function finished, get result from the stack.
+ if (ufunc->uf_ret_type == &t_void)
+ {
+ rettv->v_type = VAR_VOID;
+ }
+ else
+ {
+ tv = STACK_TV_BOT(-1);
+ *rettv = *tv;
+ tv->v_type = VAR_UNKNOWN;
+ }
}
- ret = OK;
-failed:
// When failed need to unwind the call stack.
- while (ectx.ec_frame_idx != initial_frame_idx)
- func_return(&funclocal, &ectx);
+ while (ectx.ec_frame_idx != ectx.ec_initial_frame_idx)
+ func_return(&ectx);
// Deal with any remaining closures, they may be in use somewhere.
if (ectx.ec_funcrefs.ga_len > 0)
@@ -4162,11 +4260,11 @@ failed:
}
msg_list = saved_msg_list;
- if (funclocal.floc_restore_cmdmod)
+ if (ectx.ec_funclocal.floc_restore_cmdmod)
{
cmdmod.cmod_filter_regmatch.regprog = NULL;
undo_cmdmod(&cmdmod);
- cmdmod = funclocal.floc_save_cmdmod;
+ cmdmod = ectx.ec_funclocal.floc_save_cmdmod;
}
emsg_silent_def = save_emsg_silent_def;
did_emsg_def += save_did_emsg_def;
@@ -4199,149 +4297,101 @@ failed_early:
}
/*
- * ":disassemble".
- * We don't really need this at runtime, but we do have tests that require it,
- * so always include this.
+ * List instructions "instr" up to "instr_count" or until ISN_FINISH.
+ * "ufunc" has the source lines, NULL for the instructions of ISN_SUBSTITUTE.
+ * "pfx" is prefixed to every line.
*/
- void
-ex_disassemble(exarg_T *eap)
+ static void
+list_instructions(char *pfx, isn_T *instr, int instr_count, ufunc_T *ufunc)
{
- char_u *arg = eap->arg;
- char_u *fname;
- ufunc_T *ufunc;
- dfunc_T *dfunc;
- isn_T *instr;
- int instr_count;
- int current;
int line_idx = 0;
int prev_current = 0;
- int is_global = FALSE;
-
- if (STRNCMP(arg, "<lambda>", 8) == 0)
- {
- arg += 8;
- (void)getdigits(&arg);
- fname = vim_strnsave(eap->arg, arg - eap->arg);
- }
- else
- fname = trans_function_name(&arg, &is_global, FALSE,
- TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD, NULL, NULL, NULL);
- if (fname == NULL)
- {
- semsg(_(e_invarg2), eap->arg);
- return;
- }
-
- ufunc = find_func(fname, is_global, NULL);
- if (ufunc == NULL)
- {
- char_u *p = untrans_function_name(fname);
-
- if (p != NULL)
- // Try again without making it script-local.
- ufunc = find_func(p, FALSE, NULL);
- }
- vim_free(fname);
- if (ufunc == NULL)
- {
- semsg(_(e_cannot_find_function_str), eap->arg);
- return;
- }
- if (func_needs_compiling(ufunc, eap->forceit)
- && compile_def_function(ufunc, FALSE, eap->forceit, NULL) == FAIL)
- return;
- if (ufunc->uf_def_status != UF_COMPILED)
- {
- semsg(_(e_function_is_not_compiled_str), eap->arg);
- return;
- }
- if (ufunc->uf_name_exp != NULL)
- msg((char *)ufunc->uf_name_exp);
- else
- msg((char *)ufunc->uf_name);
+ int current;
- dfunc = ((dfunc_T *)def_functions.ga_data) + ufunc->uf_dfunc_idx;
-#ifdef FEAT_PROFILE
- instr = eap->forceit ? dfunc->df_instr_prof : dfunc->df_instr;
- instr_count = eap->forceit ? dfunc->df_instr_prof_count
- : dfunc->df_instr_count;
-#else
- instr = dfunc->df_instr;
- instr_count = dfunc->df_instr_count;
-#endif
for (current = 0; current < instr_count; ++current)
{
isn_T *iptr = &instr[current];
char *line;
- while (line_idx < iptr->isn_lnum && line_idx < ufunc->uf_lines.ga_len)
- {
- if (current > prev_current)
+ if (ufunc != NULL)
+ while (line_idx < iptr->isn_lnum
+ && line_idx < ufunc->uf_lines.ga_len)
{
- msg_puts("\n\n");
- prev_current = current;
+ if (current > prev_current)
+ {
+ msg_puts("\n\n");
+ prev_current = current;
+ }
+ line = ((char **)ufunc->uf_lines.ga_data)[line_idx++];
+ if (line != NULL)
+ msg(line);
}
- line = ((char **)ufunc->uf_lines.ga_data)[line_idx++];
- if (line != NULL)
- msg(line);
- }
switch (iptr->isn_type)
{
case ISN_EXEC:
- smsg("%4d EXEC %s", current, iptr->isn_arg.string);
+ smsg("%s%4d EXEC %s", pfx, current, iptr->isn_arg.string);
+ break;
+ case ISN_SUBSTITUTE:
+ {
+ subs_T *subs = &iptr->isn_arg.subs;
+
+ smsg("%s%4d SUBSTITUTE %s", pfx, current, subs->subs_cmd);
+ list_instructions(" ", subs->subs_instr, INT_MAX, NULL);
+ msg(" -------------");
+ }
break;
case ISN_EXECCONCAT:
- smsg("%4d EXECCONCAT %lld", current,
+ smsg("%s%4d EXECCONCAT %lld", pfx, current,
(varnumber_T)iptr->isn_arg.number);
break;
case ISN_ECHO:
{
echo_T *echo = &iptr->isn_arg.echo;
- smsg("%4d %s %d", current,
+ smsg("%s%4d %s %d", pfx, current,
echo->echo_with_white ? "ECHO" : "ECHON",
echo->echo_count);
}
break;
case ISN_EXECUTE:
- smsg("%4d EXECUTE %lld", current,
+ smsg("%s%4d EXECUTE %lld", pfx, current,
(varnumber_T)(iptr->isn_arg.number));
break;
case ISN_ECHOMSG:
- smsg("%4d ECHOMSG %lld", current,
+ smsg("%s%4d ECHOMSG %lld", pfx, current,
(varnumber_T)(iptr->isn_arg.number));
break;
case ISN_ECHOERR:
- smsg("%4d ECHOERR %lld", current,
+ smsg("%s%4d ECHOERR %lld", pfx, current,
(varnumber_T)(iptr->isn_arg.number));
break;
case ISN_LOAD:
{
if (iptr->isn_arg.number < 0)
- smsg("%4d LOAD arg[%lld]", current,
+ smsg("%s%4d LOAD arg[%lld]", pfx, current,
(varnumber_T)(iptr->isn_arg.number
+ STACK_FRAME_SIZE));
else
- smsg("%4d LOAD $%lld", current,
+ smsg("%s%4d LOAD $%lld", pfx, current,
(varnumber_T)(iptr->isn_arg.number));
}
break;
case ISN_LOADOUTER:
{
if (iptr->isn_arg.number < 0)
- smsg("%4d LOADOUTER level %d arg[%d]", current,
+ smsg("%s%4d LOADOUTER level %d arg[%d]", pfx, current,
iptr->isn_arg.outer.outer_depth,
iptr->isn_arg.outer.outer_idx
+ STACK_FRAME_SIZE);
else
- smsg("%4d LOADOUTER level %d $%d", current,
+ smsg("%s%4d LOADOUTER level %d $%d", pfx, current,
iptr->isn_arg.outer.outer_depth,
iptr->isn_arg.outer.outer_idx);
}
break;
case ISN_LOADV:
- smsg("%4d LOADV v:%s", current,
+ smsg("%s%4d LOADV v:%s", pfx, current,
get_vim_var_name(iptr->isn_arg.number));
break;
case ISN_LOADSCRIPT:
@@ -4351,7 +4401,7 @@ ex_disassemble(exarg_T *eap)
svar_T *sv = ((svar_T *)si->sn_var_vals.ga_data)
+ sref->sref_idx;
- smsg("%4d LOADSCRIPT %s-%d from %s", current,
+ smsg("%s%4d LOADSCRIPT %s-%d from %s", pfx, current,
sv->sv_name,
sref->sref_idx,
si->sn_name);
@@ -4362,91 +4412,91 @@ ex_disassemble(exarg_T *eap)
scriptitem_T *si = SCRIPT_ITEM(
iptr->isn_arg.loadstore.ls_sid);
- smsg("%4d LOADS s:%s from %s", current,
+ smsg("%s%4d LOADS s:%s from %s", pfx, current,
iptr->isn_arg.loadstore.ls_name, si->sn_name);
}
break;
case ISN_LOADAUTO:
- smsg("%4d LOADAUTO %s", current, iptr->isn_arg.string);
+ smsg("%s%4d LOADAUTO %s", pfx, current, iptr->isn_arg.string);
break;
case ISN_LOADG:
- smsg("%4d LOADG g:%s", current, iptr->isn_arg.string);
+ smsg("%s%4d LOADG g:%s", pfx, current, iptr->isn_arg.string);
break;
case ISN_LOADB:
- smsg("%4d LOADB b:%s", current, iptr->isn_arg.string);
+ smsg("%s%4d LOADB b:%s", pfx, current, iptr->isn_arg.string);
break;
case ISN_LOADW:
- smsg("%4d LOADW w:%s", current, iptr->isn_arg.string);
+ smsg("%s%4d LOADW w:%s", pfx, current, iptr->isn_arg.string);
break;
case ISN_LOADT:
- smsg("%4d LOADT t:%s", current, iptr->isn_arg.string);
+ smsg("%s%4d LOADT t:%s", pfx, current, iptr->isn_arg.string);
break;
case ISN_LOADGDICT:
- smsg("%4d LOAD g:", current);
+ smsg("%s%4d LOAD g:", pfx, current);
break;
case ISN_LOADBDICT:
- smsg("%4d LOAD b:", current);
+ smsg("%s%4d LOAD b:", pfx, current);
break;
case ISN_LOADWDICT:
- smsg("%4d LOAD w:", current);
+ smsg("%s%4d LOAD w:", pfx, current);
break;
case ISN_LOADTDICT:
- smsg("%4d LOAD t:", current);
+ smsg("%s%4d LOAD t:", pfx, current);
break;
case ISN_LOADOPT:
- smsg("%4d LOADOPT %s", current, iptr->isn_arg.string);
+ smsg("%s%4d LOADOPT %s", pfx, current, iptr->isn_arg.string);
break;
case ISN_LOADENV:
- smsg("%4d LOADENV %s", current, iptr->isn_arg.string);
+ smsg("%s%4d LOADENV %s", pfx, current, iptr->isn_arg.string);
break;
case ISN_LOADREG:
- smsg("%4d LOADREG @%c", current, (int)(iptr->isn_arg.number));
+ smsg("%s%4d LOADREG @%c", pfx, current, (int)(iptr->isn_arg.number));
break;
case ISN_STORE:
if (iptr->isn_arg.number < 0)
- smsg("%4d STORE arg[%lld]", current,
+ smsg("%s%4d STORE arg[%lld]", pfx, current,
iptr->isn_arg.number + STACK_FRAME_SIZE);
else
- smsg("%4d STORE $%lld", current, iptr->isn_arg.number);
+ smsg("%s%4d STORE $%lld", pfx, current, iptr->isn_arg.number);
break;
case ISN_STOREOUTER:
{
if (iptr->isn_arg.number < 0)
- smsg("%4d STOREOUTEr level %d arg[%d]", current,
+ smsg("%s%4d STOREOUTEr level %d arg[%d]", pfx, current,
iptr->isn_arg.outer.outer_depth,
iptr->isn_arg.outer.outer_idx + STACK_FRAME_SIZE);
else
- smsg("%4d STOREOUTER level %d $%d", current,
+ smsg("%s%4d STOREOUTER level %d $%d", pfx, current,
iptr->isn_arg.outer.outer_depth,
iptr->isn_arg.outer.outer_idx);
}
break;
case ISN_STOREV:
- smsg("%4d STOREV v:%s", current,
+ smsg("%s%4d STOREV v:%s", pfx, current,
get_vim_var_name(iptr->isn_arg.number));
break;
case ISN_STOREAUTO:
- smsg("%4d STOREAUTO %s", current, iptr->isn_arg.string);
+ smsg("%s%4d STOREAUTO %s", pfx, current, iptr->isn_arg.string);
break;
case ISN_STOREG:
- smsg("%4d STOREG %s", current, iptr->isn_arg.string);
+ smsg("%s%4d STOREG %s", pfx, current, iptr->isn_arg.string);
break;
case ISN_STOREB:
- smsg("%4d STOREB %s", current, iptr->isn_arg.string);
+ smsg("%s%4d STOREB %s", pfx, current, iptr->isn_arg.string);
break;
case ISN_STOREW:
- smsg("%4d STOREW %s", current, iptr->isn_arg.string);
+ smsg("%s%4d STOREW %s", pfx, current, iptr->isn_arg.string);
break;
case ISN_STORET:
- smsg("%4d STORET %s", current, iptr->isn_arg.string);
+ smsg("%s%4d STORET %s", pfx, current, iptr->isn_arg.string);
break;
case ISN_STORES:
{
scriptitem_T *si = SCRIPT_ITEM(
iptr->isn_arg.loadstore.ls_sid);
- smsg("%4d STORES %s in %s", current,
+ smsg("%s%4d STORES %s in %s", pfx, current,
iptr->isn_arg.loadstore.ls_name, si->sn_name);
}
break;
@@ -4457,54 +4507,54 @@ ex_disassemble(exarg_T *eap)
svar_T *sv = ((svar_T *)si->sn_var_vals.ga_data)
+ sref->sref_idx;
- smsg("%4d STORESCRIPT %s-%d in %s", current,
+ smsg("%s%4d STORESCRIPT %s-%d in %s", pfx, current,
sv->sv_name,
sref->sref_idx,
si->sn_name);
}
break;
case ISN_STOREOPT:
- smsg("%4d STOREOPT &%s", current,
+ smsg("%s%4d STOREOPT &%s", pfx, current,
iptr->isn_arg.storeopt.so_name);
break;
case ISN_STOREENV:
- smsg("%4d STOREENV $%s", current, iptr->isn_arg.string);
+ smsg("%s%4d STOREENV $%s", pfx, current, iptr->isn_arg.string);
break;
case ISN_STOREREG:
- smsg("%4d STOREREG @%c", current, (int)iptr->isn_arg.number);
+ smsg("%s%4d STOREREG @%c", pfx, current, (int)iptr->isn_arg.number);
break;
case ISN_STORENR:
- smsg("%4d STORE %lld in $%d", current,
+ smsg("%s%4d STORE %lld in $%d", pfx, current,
iptr->isn_arg.storenr.stnr_val,
iptr->isn_arg.storenr.stnr_idx);
break;
case ISN_STOREINDEX:
- smsg("%4d STOREINDEX %s", current,
+ smsg("%s%4d STOREINDEX %s", pfx, current,
vartype_name(iptr->isn_arg.vartype));
break;
case ISN_STORERANGE:
- smsg("%4d STORERANGE", current);
+ smsg("%s%4d STORERANGE", pfx, current);
break;
// constants
case ISN_PUSHNR:
- smsg("%4d PUSHNR %lld", current,
+ smsg("%s%4d PUSHNR %lld", pfx, current,
(varnumber_T)(iptr->isn_arg.number));
break;
case ISN_PUSHBOOL:
case ISN_PUSHSPEC:
- smsg("%4d PUSH %s", current,
+ smsg("%s%4d PUSH %s", pfx, current,
get_var_special_name(iptr->isn_arg.number));
break;
case ISN_PUSHF:
#ifdef FEAT_FLOAT
- smsg("%4d PUSHF %g", current, iptr->isn_arg.fnumber);
+ smsg("%s%4d PUSHF %g", pfx, current, iptr->isn_arg.fnumber);
#endif
break;
case ISN_PUSHS:
- smsg("%4d PUSHS \"%s\"", current, iptr->isn_arg.string);
+ smsg("%s%4d PUSHS \"%s\"", pfx, current, iptr->isn_arg.string);
break;
case ISN_PUSHBLOB:
{
@@ -4513,7 +4563,7 @@ ex_disassemble(exarg_T *eap)
char_u *tofree;
r = blob2string(iptr->isn_arg.blob, &tofree, numbuf);
- smsg("%4d PUSHBLOB %s", current, r);
+ smsg("%s%4d PUSHBLOB %s", pfx, current, r);
vim_free(tofree);
}
break;
@@ -4521,7 +4571,7 @@ ex_disassemble(exarg_T *eap)
{
char *name = (char *)iptr->isn_arg.string;
- smsg("%4d PUSHFUNC \"%s\"", current,
+ smsg("%s%4d PUSHFUNC \"%s\"", pfx, current,
name == NULL ? "[none]" : name);
}
break;
@@ -4530,7 +4580,7 @@ ex_disassemble(exarg_T *eap)
{
channel_T *channel = iptr->isn_arg.channel;
- smsg("%4d PUSHCHANNEL %d", current,
+ smsg("%s%4d PUSHCHANNEL %d", pfx, current,
channel == NULL ? 0 : channel->ch_id);
}
#endif
@@ -4544,38 +4594,38 @@ ex_disassemble(exarg_T *eap)
tv.v_type = VAR_JOB;
tv.vval.v_job = iptr->isn_arg.job;
name = tv_get_string(&tv);
- smsg("%4d PUSHJOB \"%s\"", current, name);
+ smsg("%s%4d PUSHJOB \"%s\"", pfx, current, name);
}
#endif
break;
case ISN_PUSHEXC:
- smsg("%4d PUSH v:exception", current);
+ smsg("%s%4d PUSH v:exception", pfx, current);
break;
case ISN_UNLET:
- smsg("%4d UNLET%s %s", current,
+ smsg("%s%4d UNLET%s %s", pfx, current,
iptr->isn_arg.unlet.ul_forceit ? "!" : "",
iptr->isn_arg.unlet.ul_name);
break;
case ISN_UNLETENV:
- smsg("%4d UNLETENV%s $%s", current,
+ smsg("%s%4d UNLETENV%s $%s", pfx, current,
iptr->isn_arg.unlet.ul_forceit ? "!" : "",
iptr->isn_arg.unlet.ul_name);
break;
case ISN_UNLETINDEX:
- smsg("%4d UNLETINDEX", current);
+ smsg("%s%4d UNLETINDEX", pfx, current);
break;
case ISN_UNLETRANGE:
- smsg("%4d UNLETRANGE", current);
+ smsg("%s%4d UNLETRANGE", pfx, current);
break;
case ISN_LOCKCONST:
- smsg("%4d LOCKCONST", current);
+ smsg("%s%4d LOCKCONST", pfx, current);
break;
case ISN_NEWLIST:
- smsg("%4d NEWLIST size %lld", current,
+ smsg("%s%4d NEWLIST size %lld", pfx, current,
(varnumber_T)(iptr->isn_arg.number));
break;
case ISN_NEWDICT:
- smsg("%4d NEWDICT size %lld", current,
+ smsg("%s%4d NEWDICT size %lld", pfx, current,
(varnumber_T)(iptr->isn_arg.number));
break;
@@ -4584,7 +4634,7 @@ ex_disassemble(exarg_T *eap)
{
cbfunc_T *cbfunc = &iptr->isn_arg.bfunc;
- smsg("%4d BCALL %s(argc %d)", current,
+ smsg("%s%4d BCALL %s(argc %d)", pfx, current,
internal_func_name(cbfunc->cbf_idx),
cbfunc->cbf_argcount);
}
@@ -4595,7 +4645,7 @@ ex_disassemble(exarg_T *eap)
dfunc_T *df = ((dfunc_T *)def_functions.ga_data)
+ cdfunc->cdf_idx;
- smsg("%4d DCALL %s(argc %d)", current,
+ smsg("%s%4d DCALL %s(argc %d)", pfx, current,
df->df_ufunc->uf_name_exp != NULL
? df->df_ufunc->uf_name_exp
: df->df_ufunc->uf_name, cdfunc->cdf_argcount);
@@ -4605,7 +4655,7 @@ ex_disassemble(exarg_T *eap)
{
cufunc_T *cufunc = &iptr->isn_arg.ufunc;
- smsg("%4d UCALL %s(argc %d)", current,
+ smsg("%s%4d UCALL %s(argc %d)", pfx, current,
cufunc->cuf_name, cufunc->cuf_argcount);
}
break;
@@ -4613,18 +4663,18 @@ ex_disassemble(exarg_T *eap)
{
cpfunc_T *cpfunc = &iptr->isn_arg.pfunc;
- smsg("%4d PCALL%s (argc %d)", current,
+ smsg("%s%4d PCALL%s (argc %d)", pfx, current,
cpfunc->cpf_top ? " top" : "", cpfunc->cpf_argcount);
}
break;
case ISN_PCALL_END:
- smsg("%4d PCALL end", current);
+ smsg("%s%4d PCALL end", pfx, current);
break;
case ISN_RETURN:
- smsg("%4d RETURN", current);
+ smsg("%s%4d RETURN", pfx, current);
break;
case ISN_RETURN_ZERO:
- smsg("%4d RETURN 0", current);
+ smsg("%s%4d RETURN 0", pfx, current);
break;
case ISN_FUNCREF:
{
@@ -4632,7 +4682,7 @@ ex_disassemble(exarg_T *eap)
dfunc_T *df = ((dfunc_T *)def_functions.ga_data)
+ funcref->fr_func;
- smsg("%4d FUNCREF %s", current, df->df_ufunc->uf_name);
+ smsg("%s%4d FUNCREF %s", pfx, current, df->df_ufunc->uf_name);
}
break;
@@ -4640,7 +4690,7 @@ ex_disassemble(exarg_T *eap)
{
newfunc_T *newfunc = &iptr->isn_arg.newfunc;
- smsg("%4d NEWFUNC %s %s", current,
+ smsg("%s%4d NEWFUNC %s %s", pfx, current,
newfunc->nf_lambda, newfunc->nf_global);
}
break;
@@ -4649,7 +4699,7 @@ ex_disassemble(exarg_T *eap)
{
char_u *name = iptr->isn_arg.string;
- smsg("%4d DEF %s", current,
+ smsg("%s%4d DEF %s", pfx, current,
name == NULL ? (char_u *)"" : name);
}
break;
@@ -4679,13 +4729,13 @@ ex_disassemble(exarg_T *eap)
when = "JUMP_IF_COND_TRUE";
break;
}
- smsg("%4d %s -> %d", current, when,
+ smsg("%s%4d %s -> %d", pfx, current, when,
iptr->isn_arg.jump.jump_where);
}
break;
case ISN_JUMP_IF_ARG_SET:
- smsg("%4d JUMP_IF_ARG_SET arg[%d] -> %d", current,
+ smsg("%s%4d JUMP_IF_ARG_SET arg[%d] -> %d", pfx, current,
iptr->isn_arg.jumparg.jump_arg_off + STACK_FRAME_SIZE,
iptr->isn_arg.jump.jump_where);
break;
@@ -4694,7 +4744,7 @@ ex_disassemble(exarg_T *eap)
{
forloop_T *forloop = &iptr->isn_arg.forloop;
- smsg("%4d FOR $%d -> %d", current,
+ smsg("%s%4d FOR $%d -> %d", pfx, current,
forloop->for_idx, forloop->for_end);
}
break;
@@ -4704,13 +4754,13 @@ ex_disassemble(exarg_T *eap)
try_T *try = &iptr->isn_arg.try;
if (try->try_ref->try_finally == 0)
- smsg("%4d TRY catch -> %d, endtry -> %d",
- current,
+ smsg("%s%4d TRY catch -> %d, endtry -> %d",
+ pfx, current,
try->try_ref->try_catch,
try->try_ref->try_endtry);
else
- smsg("%4d TRY catch -> %d, finally -> %d, endtry -> %d",
- current,
+ smsg("%s%4d TRY catch -> %d, finally -> %d, endtry -> %d",
+ pfx, current,
try->try_ref->try_catch,
try->try_ref->try_finally,
try->try_ref->try_endtry);
@@ -4718,26 +4768,26 @@ ex_disassemble(exarg_T *eap)
break;
case ISN_CATCH:
// TODO
- smsg("%4d CATCH", current);
+ smsg("%s%4d CATCH", pfx, current);
break;
case ISN_TRYCONT:
{
trycont_T *trycont = &iptr->isn_arg.trycont;
- smsg("%4d TRY-CONTINUE %d level%s -> %d", current,
+ smsg("%s%4d TRY-CONTINUE %d level%s -> %d", pfx, current,
trycont->tct_levels,
trycont->tct_levels == 1 ? "" : "s",
trycont->tct_where);
}
break;
case ISN_FINALLY:
- smsg("%4d FINALLY", current);
+ smsg("%s%4d FINALLY", pfx, current);
break;
case ISN_ENDTRY:
- smsg("%4d ENDTRY", current);
+ smsg("%s%4d ENDTRY", pfx, current);
break;
case ISN_THROW:
- smsg("%4d THROW", current);
+ smsg("%s%4d THROW", pfx, current);
break;
// expression operations on number
@@ -4764,7 +4814,7 @@ ex_disassemble(exarg_T *eap)
case ISN_OPANY: ins = "OPANY"; break;
default: ins = "???"; break;
}
- smsg("%4d %s %s", current, ins, what);
+ smsg("%s%4d %s %s", pfx, current, ins, what);
}
break;
@@ -4817,53 +4867,53 @@ ex_disassemble(exarg_T *eap)
default: type = "???"; break;
}
- smsg("%4d %s %s", current, type, buf);
+ smsg("%s%4d %s %s", pfx, current, type, buf);
}
break;
- case ISN_ADDLIST: smsg("%4d ADDLIST", current); break;
- case ISN_ADDBLOB: smsg("%4d ADDBLOB", current); break;
+ case ISN_ADDLIST: smsg("%s%4d ADDLIST", pfx, current); break;
+ case ISN_ADDBLOB: smsg("%s%4d ADDBLOB", pfx, current); break;
// expression operations
- case ISN_CONCAT: smsg("%4d CONCAT", current); break;
- case ISN_STRINDEX: smsg("%4d STRINDEX", current); break;
- case ISN_STRSLICE: smsg("%4d STRSLICE", current); break;
- case ISN_BLOBINDEX: smsg("%4d BLOBINDEX", current); break;
- case ISN_BLOBSLICE: smsg("%4d BLOBSLICE", current); break;
- case ISN_LISTAPPEND: smsg("%4d LISTAPPEND", current); break;
- case ISN_BLOBAPPEND: smsg("%4d BLOBAPPEND", current); break;
- case ISN_LISTINDEX: smsg("%4d LISTINDEX", current); break;
- case ISN_LISTSLICE: smsg("%4d LISTSLICE", current); break;
- case ISN_ANYINDEX: smsg("%4d ANYINDEX", current); break;
- case ISN_ANYSLICE: smsg("%4d ANYSLICE", current); break;
- case ISN_SLICE: smsg("%4d SLICE %lld",
- current, iptr->isn_arg.number); break;
- case ISN_GETITEM: smsg("%4d ITEM %lld",
- current, iptr->isn_arg.number); break;
- case ISN_MEMBER: smsg("%4d MEMBER", current); break;
- case ISN_STRINGMEMBER: smsg("%4d MEMBER %s", current,
+ case ISN_CONCAT: smsg("%s%4d CONCAT", pfx, current); break;
+ case ISN_STRINDEX: smsg("%s%4d STRINDEX", pfx, current); break;
+ case ISN_STRSLICE: smsg("%s%4d STRSLICE", pfx, current); break;
+ case ISN_BLOBINDEX: smsg("%s%4d BLOBINDEX", pfx, current); break;
+ case ISN_BLOBSLICE: smsg("%s%4d BLOBSLICE", pfx, current); break;
+ case ISN_LISTAPPEND: smsg("%s%4d LISTAPPEND", pfx, current); break;
+ case ISN_BLOBAPPEND: smsg("%s%4d BLOBAPPEND", pfx, current); break;
+ case ISN_LISTINDEX: smsg("%s%4d LISTINDEX", pfx, current); break;
+ case ISN_LISTSLICE: smsg("%s%4d LISTSLICE", pfx, current); break;
+ case ISN_ANYINDEX: smsg("%s%4d ANYINDEX", pfx, current); break;
+ case ISN_ANYSLICE: smsg("%s%4d ANYSLICE", pfx, current); break;
+ case ISN_SLICE: smsg("%s%4d SLICE %lld",
+ pfx, current, iptr->isn_arg.number); break;
+ case ISN_GETITEM: smsg("%s%4d ITEM %lld",
+ pfx, current, iptr->isn_arg.number); break;
+ case ISN_MEMBER: smsg("%s%4d MEMBER", pfx, current); break;
+ case ISN_STRINGMEMBER: smsg("%s%4d MEMBER %s", pfx, current,
iptr->isn_arg.string); break;
- case ISN_NEGATENR: smsg("%4d NEGATENR", current); break;
+ case ISN_NEGATENR: smsg("%s%4d NEGATENR", pfx, current); break;
- case ISN_CHECKNR: smsg("%4d CHECKNR", current); break;
+ case ISN_CHECKNR: smsg("%s%4d CHECKNR", pfx, current); break;
case ISN_CHECKTYPE:
{
checktype_T *ct = &iptr->isn_arg.type;
char *tofree;
if (ct->ct_arg_idx == 0)
- smsg("%4d CHECKTYPE %s stack[%d]", current,
+ smsg("%s%4d CHECKTYPE %s stack[%d]", pfx, current,
type_name(ct->ct_type, &tofree),
(int)ct->ct_off);
else
- smsg("%4d CHECKTYPE %s stack[%d] arg %d", current,
+ smsg("%s%4d CHECKTYPE %s stack[%d] arg %d", pfx, current,
type_name(ct->ct_type, &tofree),
(int)ct->ct_off,
(int)ct->ct_arg_idx);
vim_free(tofree);
break;
}
- case ISN_CHECKLEN: smsg("%4d CHECKLEN %s%d", current,
+ case ISN_CHECKLEN: smsg("%s%4d CHECKLEN %s%d", pfx, current,
iptr->isn_arg.checklen.cl_more_OK ? ">= " : "",
iptr->isn_arg.checklen.cl_min_len);
break;
@@ -4871,34 +4921,34 @@ ex_disassemble(exarg_T *eap)
{
char *tofree;
- smsg("%4d SETTYPE %s", current,
+ smsg("%s%4d SETTYPE %s", pfx, current,
type_name(iptr->isn_arg.type.ct_type, &tofree));
vim_free(tofree);
break;
}
- case ISN_COND2BOOL: smsg("%4d COND2BOOL", current); break;
+ case ISN_COND2BOOL: smsg("%s%4d COND2BOOL", pfx, current); break;
case ISN_2BOOL: if (iptr->isn_arg.number)
- smsg("%4d INVERT (!val)", current);
+ smsg("%s%4d INVERT (!val)", pfx, current);
else
- smsg("%4d 2BOOL (!!val)", current);
+ smsg("%s%4d 2BOOL (!!val)", pfx, current);
break;
- case ISN_2STRING: smsg("%4d 2STRING stack[%lld]", current,
+ case ISN_2STRING: smsg("%s%4d 2STRING stack[%lld]", pfx, current,
(varnumber_T)(iptr->isn_arg.number));
break;
- case ISN_2STRING_ANY: smsg("%4d 2STRING_ANY stack[%lld]", current,
+ case ISN_2STRING_ANY: smsg("%s%4d 2STRING_ANY stack[%lld]", pfx, current,
(varnumber_T)(iptr->isn_arg.number));
break;
- case ISN_RANGE: smsg("%4d RANGE %s", current, iptr->isn_arg.string);
+ case ISN_RANGE: smsg("%s%4d RANGE %s", pfx, current, iptr->isn_arg.string);
break;
case ISN_PUT:
if (iptr->isn_arg.put.put_lnum == LNUM_VARIABLE_RANGE_ABOVE)
- smsg("%4d PUT %c above range",
- current, iptr->isn_arg.put.put_regname);
+ smsg("%s%4d PUT %c above range",
+ pfx, current, iptr->isn_arg.put.put_regname);
else if (iptr->isn_arg.put.put_lnum == LNUM_VARIABLE_RANGE)
- smsg("%4d PUT %c range",
- current, iptr->isn_arg.put.put_regname);
+ smsg("%s%4d PUT %c range",
+ pfx, current, iptr->isn_arg.put.put_regname);
else
- smsg("%4d PUT %c %ld", current,
+ smsg("%s%4d PUT %c %ld", pfx, current,
iptr->isn_arg.put.put_regname,
(long)iptr->isn_arg.put.put_lnum);
break;
@@ -4915,30 +4965,33 @@ ex_disassemble(exarg_T *eap)
{
(void)produce_cmdmods(
buf, iptr->isn_arg.cmdmod.cf_cmdmod, FALSE);
- smsg("%4d CMDMOD %s", current, buf);
+ smsg("%s%4d CMDMOD %s", pfx, current, buf);
vim_free(buf);
}
break;
}
- case ISN_CMDMOD_REV: smsg("%4d CMDMOD_REV", current); break;
+ case ISN_CMDMOD_REV: smsg("%s%4d CMDMOD_REV", pfx, current); break;
case ISN_PROF_START:
- smsg("%4d PROFILE START line %d", current, iptr->isn_lnum);
+ smsg("%s%4d PROFILE START line %d", pfx, current, iptr->isn_lnum);
break;
case ISN_PROF_END:
- smsg("%4d PROFILE END", current);
+ smsg("%s%4d PROFILE END", pfx, current);
break;
- case ISN_UNPACK: smsg("%4d UNPACK %d%s", current,
+ case ISN_UNPACK: smsg("%s%4d UNPACK %d%s", pfx, current,
iptr->isn_arg.unpack.unp_count,
iptr->isn_arg.unpack.unp_semicolon ? " semicolon" : "");
break;
- case ISN_SHUFFLE: smsg("%4d SHUFFLE %d up %d", current,
+ case ISN_SHUFFLE: smsg("%s%4d SHUFFLE %d up %d", pfx, current,
iptr->isn_arg.shuffle.shfl_item,
iptr->isn_arg.shuffle.shfl_up);
break;
- case ISN_DROP: smsg("%4d DROP", current); break;
+ case ISN_DROP: smsg("%s%4d DROP", pfx, current); break;
+
+ case ISN_FINISH: // End of list of instructions for ISN_SUBSTITUTE.
+ return;
}
out_flush(); // output one line at a time
@@ -4949,6 +5002,78 @@ ex_disassemble(exarg_T *eap)
}
/*
+ * ":disassemble".
+ * We don't really need this at runtime, but we do have tests that require it,
+ * so always include this.
+ */
+ void
+ex_disassemble(exarg_T *eap)
+{
+ char_u *arg = eap->arg;
+ char_u *fname;
+ ufunc_T *ufunc;
+ dfunc_T *dfunc;
+ isn_T *instr;
+ int instr_count;
+ int is_global = FALSE;
+
+ if (STRNCMP(arg, "<lambda>", 8) == 0)
+ {
+ arg += 8;
+ (void)getdigits(&arg);
+ fname = vim_strnsave(eap->arg, arg - eap->arg);
+ }
+ else
+ fname = trans_function_name(&arg, &is_global, FALSE,
+ TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD, NULL, NULL, NULL);
+ if (fname == NULL)
+ {
+ semsg(_(e_invarg2), eap->arg);
+ return;
+ }
+
+ ufunc = find_func(fname, is_global, NULL);
+ if (ufunc == NULL)
+ {
+ char_u *p = untrans_function_name(fname);
+
+ if (p != NULL)
+ // Try again without making it script-local.
+ ufunc = find_func(p, FALSE, NULL);
+ }
+ vim_free(fname);
+ if (ufunc == NULL)
+ {
+ semsg(_(e_cannot_find_function_str), eap->arg);
+ return;
+ }
+ if (func_needs_compiling(ufunc, eap->forceit)
+ && compile_def_function(ufunc, FALSE, eap->forceit, NULL) == FAIL)
+ return;
+ if (ufunc->uf_def_status != UF_COMPILED)
+ {
+ semsg(_(e_function_is_not_compiled_str), eap->arg);
+ return;
+ }
+ if (ufunc->uf_name_exp != NULL)
+ msg((char *)ufunc->uf_name_exp);
+ else
+ msg((char *)ufunc->uf_name);
+
+ dfunc = ((dfunc_T *)def_functions.ga_data) + ufunc->uf_dfunc_idx;
+#ifdef FEAT_PROFILE
+ instr = eap->forceit ? dfunc->df_instr_prof : dfunc->df_instr;
+ instr_count = eap->forceit ? dfunc->df_instr_prof_count
+ : dfunc->df_instr_count;
+#else
+ instr = dfunc->df_instr;
+ instr_count = dfunc->df_instr_count;
+#endif
+
+ list_instructions("", instr, instr_count, ufunc);
+}
+
+/*
* Return TRUE when "tv" is not falsy: non-zero, non-empty string, non-empty
* list, etc. Mostly like what JavaScript does, except that empty list and
* empty dictionary are FALSE.