xref: /vim-8.2.3635/src/vim9execute.c (revision fc0e8f5c)
18a7d6542SBram Moolenaar /* vi:set ts=8 sts=4 sw=4 noet:
28a7d6542SBram Moolenaar  *
38a7d6542SBram Moolenaar  * VIM - Vi IMproved	by Bram Moolenaar
48a7d6542SBram Moolenaar  *
58a7d6542SBram Moolenaar  * Do ":help uganda"  in Vim to read copying and usage conditions.
68a7d6542SBram Moolenaar  * Do ":help credits" in Vim to see a list of people who contributed.
78a7d6542SBram Moolenaar  * See README.txt for an overview of the Vim source code.
88a7d6542SBram Moolenaar  */
98a7d6542SBram Moolenaar 
108a7d6542SBram Moolenaar /*
118a7d6542SBram Moolenaar  * vim9execute.c: execute Vim9 script instructions
128a7d6542SBram Moolenaar  */
138a7d6542SBram Moolenaar 
148a7d6542SBram Moolenaar #define USING_FLOAT_STUFF
158a7d6542SBram Moolenaar #include "vim.h"
168a7d6542SBram Moolenaar 
178a7d6542SBram Moolenaar #if defined(FEAT_EVAL) || defined(PROTO)
188a7d6542SBram Moolenaar 
198a7d6542SBram Moolenaar #ifdef VMS
208a7d6542SBram Moolenaar # include <float.h>
218a7d6542SBram Moolenaar #endif
228a7d6542SBram Moolenaar 
238a7d6542SBram Moolenaar #include "vim9.h"
248a7d6542SBram Moolenaar 
258a7d6542SBram Moolenaar // Structure put on ec_trystack when ISN_TRY is encountered.
268a7d6542SBram Moolenaar typedef struct {
27bf67ea1aSBram Moolenaar     int	    tcd_frame_idx;	// ec_frame_idx when ISN_TRY was encountered
288a7d6542SBram Moolenaar     int	    tcd_catch_idx;	// instruction of the first catch
298a7d6542SBram Moolenaar     int	    tcd_finally_idx;	// instruction of the finally block
308a7d6542SBram Moolenaar     int	    tcd_caught;		// catch block entered
318a7d6542SBram Moolenaar     int	    tcd_return;		// when TRUE return from end of :finally
328a7d6542SBram Moolenaar } trycmd_T;
338a7d6542SBram Moolenaar 
348a7d6542SBram Moolenaar 
358a7d6542SBram Moolenaar // A stack is used to store:
368a7d6542SBram Moolenaar // - arguments passed to a :def function
378a7d6542SBram Moolenaar // - info about the calling function, to use when returning
388a7d6542SBram Moolenaar // - local variables
398a7d6542SBram Moolenaar // - temporary values
408a7d6542SBram Moolenaar //
418a7d6542SBram Moolenaar // In detail (FP == Frame Pointer):
428a7d6542SBram Moolenaar //	  arg1		first argument from caller (if present)
438a7d6542SBram Moolenaar //	  arg2		second argument from caller (if present)
448a7d6542SBram Moolenaar //	  extra_arg1	any missing optional argument default value
458a7d6542SBram Moolenaar // FP ->  cur_func	calling function
468a7d6542SBram Moolenaar //        current	previous instruction pointer
478a7d6542SBram Moolenaar //        frame_ptr	previous Frame Pointer
488a7d6542SBram Moolenaar //        var1		space for local variable
498a7d6542SBram Moolenaar //        var2		space for local variable
508a7d6542SBram Moolenaar //        ....		fixed space for max. number of local variables
518a7d6542SBram Moolenaar //        temp		temporary values
528a7d6542SBram Moolenaar //        ....		flexible space for temporary values (can grow big)
538a7d6542SBram Moolenaar 
548a7d6542SBram Moolenaar /*
558a7d6542SBram Moolenaar  * Execution context.
568a7d6542SBram Moolenaar  */
57cd45ed03SBram Moolenaar struct ectx_S {
588a7d6542SBram Moolenaar     garray_T	ec_stack;	// stack of typval_T values
59bf67ea1aSBram Moolenaar     int		ec_frame_idx;	// index in ec_stack: context of ec_dfunc_idx
608a7d6542SBram Moolenaar 
61c8cd2b34SBram Moolenaar     garray_T	*ec_outer_stack;    // stack used for closures
62c8cd2b34SBram Moolenaar     int		ec_outer_frame;	    // stack frame in ec_outer_stack
63c8cd2b34SBram Moolenaar 
648a7d6542SBram Moolenaar     garray_T	ec_trystack;	// stack of trycmd_T values
658a7d6542SBram Moolenaar     int		ec_in_catch;	// when TRUE in catch or finally block
668a7d6542SBram Moolenaar 
678a7d6542SBram Moolenaar     int		ec_dfunc_idx;	// current function index
688a7d6542SBram Moolenaar     isn_T	*ec_instr;	// array with instructions
698a7d6542SBram Moolenaar     int		ec_iidx;	// index in ec_instr: instruction to execute
70148ce7aeSBram Moolenaar 
71148ce7aeSBram Moolenaar     garray_T	ec_funcrefs;	// partials that might be a closure
72cd45ed03SBram Moolenaar };
738a7d6542SBram Moolenaar 
748a7d6542SBram Moolenaar // Get pointer to item relative to the bottom of the stack, -1 is the last one.
7511107babSBram Moolenaar #define STACK_TV_BOT(idx) (((typval_T *)ectx->ec_stack.ga_data) + ectx->ec_stack.ga_len + (idx))
768a7d6542SBram Moolenaar 
77418f1df5SBram Moolenaar     void
78418f1df5SBram Moolenaar to_string_error(vartype_T vartype)
79418f1df5SBram Moolenaar {
80451c2e35SBram Moolenaar     semsg(_(e_cannot_convert_str_to_string), vartype_name(vartype));
81418f1df5SBram Moolenaar }
82418f1df5SBram Moolenaar 
838a7d6542SBram Moolenaar /*
84170fcfcfSBram Moolenaar  * Return the number of arguments, including optional arguments and any vararg.
858a7d6542SBram Moolenaar  */
868a7d6542SBram Moolenaar     static int
878a7d6542SBram Moolenaar ufunc_argcount(ufunc_T *ufunc)
888a7d6542SBram Moolenaar {
898a7d6542SBram Moolenaar     return ufunc->uf_args.ga_len + (ufunc->uf_va_name != NULL ? 1 : 0);
908a7d6542SBram Moolenaar }
918a7d6542SBram Moolenaar 
928a7d6542SBram Moolenaar /*
93170fcfcfSBram Moolenaar  * Set the instruction index, depending on omitted arguments, where the default
94170fcfcfSBram Moolenaar  * values are to be computed.  If all optional arguments are present, start
95170fcfcfSBram Moolenaar  * with the function body.
96170fcfcfSBram Moolenaar  * The expression evaluation is at the start of the instructions:
97170fcfcfSBram Moolenaar  *  0 ->  EVAL default1
98170fcfcfSBram Moolenaar  *	       STORE arg[-2]
99170fcfcfSBram Moolenaar  *  1 ->  EVAL default2
100170fcfcfSBram Moolenaar  *	       STORE arg[-1]
101170fcfcfSBram Moolenaar  *  2 ->  function body
102170fcfcfSBram Moolenaar  */
103170fcfcfSBram Moolenaar     static void
104170fcfcfSBram Moolenaar init_instr_idx(ufunc_T *ufunc, int argcount, ectx_T *ectx)
105170fcfcfSBram Moolenaar {
106170fcfcfSBram Moolenaar     if (ufunc->uf_def_args.ga_len == 0)
107170fcfcfSBram Moolenaar 	ectx->ec_iidx = 0;
108170fcfcfSBram Moolenaar     else
109170fcfcfSBram Moolenaar     {
110170fcfcfSBram Moolenaar 	int	defcount = ufunc->uf_args.ga_len - argcount;
111170fcfcfSBram Moolenaar 
112170fcfcfSBram Moolenaar 	// If there is a varargs argument defcount can be negative, no defaults
113170fcfcfSBram Moolenaar 	// to evaluate then.
114170fcfcfSBram Moolenaar 	if (defcount < 0)
115170fcfcfSBram Moolenaar 	    defcount = 0;
116170fcfcfSBram Moolenaar 	ectx->ec_iidx = ufunc->uf_def_arg_idx[
117170fcfcfSBram Moolenaar 					 ufunc->uf_def_args.ga_len - defcount];
118170fcfcfSBram Moolenaar     }
119170fcfcfSBram Moolenaar }
120170fcfcfSBram Moolenaar 
121170fcfcfSBram Moolenaar /*
122fe270817SBram Moolenaar  * Create a new list from "count" items at the bottom of the stack.
123fe270817SBram Moolenaar  * When "count" is zero an empty list is added to the stack.
124fe270817SBram Moolenaar  */
125fe270817SBram Moolenaar     static int
126fe270817SBram Moolenaar exe_newlist(int count, ectx_T *ectx)
127fe270817SBram Moolenaar {
128fe270817SBram Moolenaar     list_T	*list = list_alloc_with_items(count);
129fe270817SBram Moolenaar     int		idx;
130fe270817SBram Moolenaar     typval_T	*tv;
131fe270817SBram Moolenaar 
132fe270817SBram Moolenaar     if (list == NULL)
133fe270817SBram Moolenaar 	return FAIL;
134fe270817SBram Moolenaar     for (idx = 0; idx < count; ++idx)
135fe270817SBram Moolenaar 	list_set_item(list, idx, STACK_TV_BOT(idx - count));
136fe270817SBram Moolenaar 
137fe270817SBram Moolenaar     if (count > 0)
138fe270817SBram Moolenaar 	ectx->ec_stack.ga_len -= count - 1;
139270d0388SBram Moolenaar     else if (GA_GROW(&ectx->ec_stack, 1) == FAIL)
140fe270817SBram Moolenaar 	return FAIL;
141fe270817SBram Moolenaar     else
142fe270817SBram Moolenaar 	++ectx->ec_stack.ga_len;
143fe270817SBram Moolenaar     tv = STACK_TV_BOT(-1);
144fe270817SBram Moolenaar     tv->v_type = VAR_LIST;
145fe270817SBram Moolenaar     tv->vval.v_list = list;
146fe270817SBram Moolenaar     ++list->lv_refcount;
147fe270817SBram Moolenaar     return OK;
148fe270817SBram Moolenaar }
149fe270817SBram Moolenaar 
150fe270817SBram Moolenaar /*
1518a7d6542SBram Moolenaar  * Call compiled function "cdf_idx" from compiled code.
1528a7d6542SBram Moolenaar  *
1538a7d6542SBram Moolenaar  * Stack has:
1548a7d6542SBram Moolenaar  * - current arguments (already there)
1558a7d6542SBram Moolenaar  * - omitted optional argument (default values) added here
1568a7d6542SBram Moolenaar  * - stack frame:
1578a7d6542SBram Moolenaar  *	- pointer to calling function
1588a7d6542SBram Moolenaar  *	- Index of next instruction in calling function
1598a7d6542SBram Moolenaar  *	- previous frame pointer
1608a7d6542SBram Moolenaar  * - reserved space for local variables
1618a7d6542SBram Moolenaar  */
1628a7d6542SBram Moolenaar     static int
1631378fbc4SBram Moolenaar call_dfunc(int cdf_idx, int argcount_arg, ectx_T *ectx)
1648a7d6542SBram Moolenaar {
1651378fbc4SBram Moolenaar     int	    argcount = argcount_arg;
1668a7d6542SBram Moolenaar     dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data) + cdf_idx;
1678a7d6542SBram Moolenaar     ufunc_T *ufunc = dfunc->df_ufunc;
1681378fbc4SBram Moolenaar     int	    arg_to_add;
1691378fbc4SBram Moolenaar     int	    vararg_count = 0;
170148ce7aeSBram Moolenaar     int	    varcount;
1718a7d6542SBram Moolenaar     int	    idx;
172c620c055SBram Moolenaar     estack_T *entry;
1738a7d6542SBram Moolenaar 
1748a7d6542SBram Moolenaar     if (dfunc->df_deleted)
1758a7d6542SBram Moolenaar     {
176cd45ed03SBram Moolenaar 	// don't use ufunc->uf_name, it may have been freed
177cd45ed03SBram Moolenaar 	emsg_funcname(e_func_deleted,
178cd45ed03SBram Moolenaar 		dfunc->df_name == NULL ? (char_u *)"unknown" : dfunc->df_name);
1798a7d6542SBram Moolenaar 	return FAIL;
1808a7d6542SBram Moolenaar     }
1818a7d6542SBram Moolenaar 
1821378fbc4SBram Moolenaar     if (ufunc->uf_va_name != NULL)
1831378fbc4SBram Moolenaar     {
184fe270817SBram Moolenaar 	// Need to make a list out of the vararg arguments.
1851378fbc4SBram Moolenaar 	// Stack at time of call with 2 varargs:
1861378fbc4SBram Moolenaar 	//   normal_arg
1871378fbc4SBram Moolenaar 	//   optional_arg
1881378fbc4SBram Moolenaar 	//   vararg_1
1891378fbc4SBram Moolenaar 	//   vararg_2
190fe270817SBram Moolenaar 	// After creating the list:
1911378fbc4SBram Moolenaar 	//   normal_arg
1921378fbc4SBram Moolenaar 	//   optional_arg
193fe270817SBram Moolenaar 	//   vararg-list
194fe270817SBram Moolenaar 	// With missing optional arguments we get:
195fe270817SBram Moolenaar 	//    normal_arg
196fe270817SBram Moolenaar 	// After creating the list
197fe270817SBram Moolenaar 	//    normal_arg
198fe270817SBram Moolenaar 	//    (space for optional_arg)
199fe270817SBram Moolenaar 	//    vararg-list
2001378fbc4SBram Moolenaar 	vararg_count = argcount - ufunc->uf_args.ga_len;
2011378fbc4SBram Moolenaar 	if (vararg_count < 0)
2021378fbc4SBram Moolenaar 	    vararg_count = 0;
2031378fbc4SBram Moolenaar 	else
2041378fbc4SBram Moolenaar 	    argcount -= vararg_count;
205fe270817SBram Moolenaar 	if (exe_newlist(vararg_count, ectx) == FAIL)
2061378fbc4SBram Moolenaar 	    return FAIL;
207fe270817SBram Moolenaar 
208fe270817SBram Moolenaar 	vararg_count = 1;
2091378fbc4SBram Moolenaar     }
2101378fbc4SBram Moolenaar 
211fe270817SBram Moolenaar     arg_to_add = ufunc->uf_args.ga_len - argcount;
2121378fbc4SBram Moolenaar     if (arg_to_add < 0)
2131378fbc4SBram Moolenaar     {
21479e8db9aSBram Moolenaar 	if (arg_to_add == -1)
215451c2e35SBram Moolenaar 	    emsg(_(e_one_argument_too_many));
21679e8db9aSBram Moolenaar 	else
217451c2e35SBram Moolenaar 	    semsg(_(e_nr_arguments_too_many), -arg_to_add);
2181378fbc4SBram Moolenaar 	return FAIL;
2191378fbc4SBram Moolenaar     }
220148ce7aeSBram Moolenaar 
221148ce7aeSBram Moolenaar     // Reserve space for:
222148ce7aeSBram Moolenaar     // - missing arguments
223148ce7aeSBram Moolenaar     // - stack frame
224148ce7aeSBram Moolenaar     // - local variables
225148ce7aeSBram Moolenaar     // - if needed: a counter for number of closures created in
226148ce7aeSBram Moolenaar     //   ectx->ec_funcrefs.
227148ce7aeSBram Moolenaar     varcount = dfunc->df_varcount + dfunc->df_has_closure;
228148ce7aeSBram Moolenaar     if (ga_grow(&ectx->ec_stack, arg_to_add + STACK_FRAME_SIZE + varcount)
229148ce7aeSBram Moolenaar 								       == FAIL)
2308a7d6542SBram Moolenaar 	return FAIL;
2318a7d6542SBram Moolenaar 
2320ba48e8cSBram Moolenaar     // If depth of calling is getting too high, don't execute the function.
2330ba48e8cSBram Moolenaar     if (funcdepth_increment() == FAIL)
2340ba48e8cSBram Moolenaar 	return FAIL;
2350ba48e8cSBram Moolenaar 
236fe270817SBram Moolenaar     // Move the vararg-list to below the missing optional arguments.
237fe270817SBram Moolenaar     if (vararg_count > 0 && arg_to_add > 0)
238fe270817SBram Moolenaar 	*STACK_TV_BOT(arg_to_add - 1) = *STACK_TV_BOT(-1);
239170fcfcfSBram Moolenaar 
240170fcfcfSBram Moolenaar     // Reserve space for omitted optional arguments, filled in soon.
2411378fbc4SBram Moolenaar     for (idx = 0; idx < arg_to_add; ++idx)
242fe270817SBram Moolenaar 	STACK_TV_BOT(idx - vararg_count)->v_type = VAR_UNKNOWN;
2431378fbc4SBram Moolenaar     ectx->ec_stack.ga_len += arg_to_add;
2448a7d6542SBram Moolenaar 
2458a7d6542SBram Moolenaar     // Store current execution state in stack frame for ISN_RETURN.
2468a7d6542SBram Moolenaar     STACK_TV_BOT(0)->vval.v_number = ectx->ec_dfunc_idx;
2478a7d6542SBram Moolenaar     STACK_TV_BOT(1)->vval.v_number = ectx->ec_iidx;
2485366e1aeSBram Moolenaar     STACK_TV_BOT(2)->vval.v_string = (void *)ectx->ec_outer_stack;
2495366e1aeSBram Moolenaar     STACK_TV_BOT(3)->vval.v_number = ectx->ec_outer_frame;
2505366e1aeSBram Moolenaar     STACK_TV_BOT(4)->vval.v_number = ectx->ec_frame_idx;
251bf67ea1aSBram Moolenaar     ectx->ec_frame_idx = ectx->ec_stack.ga_len;
2528a7d6542SBram Moolenaar 
2538a7d6542SBram Moolenaar     // Initialize local variables
254148ce7aeSBram Moolenaar     for (idx = 0; idx < dfunc->df_varcount; ++idx)
2558a7d6542SBram Moolenaar 	STACK_TV_BOT(STACK_FRAME_SIZE + idx)->v_type = VAR_UNKNOWN;
256148ce7aeSBram Moolenaar     if (dfunc->df_has_closure)
257148ce7aeSBram Moolenaar     {
258148ce7aeSBram Moolenaar 	typval_T *tv = STACK_TV_BOT(STACK_FRAME_SIZE + dfunc->df_varcount);
259148ce7aeSBram Moolenaar 
260148ce7aeSBram Moolenaar 	tv->v_type = VAR_NUMBER;
261148ce7aeSBram Moolenaar 	tv->vval.v_number = 0;
262148ce7aeSBram Moolenaar     }
263148ce7aeSBram Moolenaar     ectx->ec_stack.ga_len += STACK_FRAME_SIZE + varcount;
2648a7d6542SBram Moolenaar 
265cd45ed03SBram Moolenaar     if (ufunc->uf_partial != NULL)
266cd45ed03SBram Moolenaar     {
267cd45ed03SBram Moolenaar 	ectx->ec_outer_stack = ufunc->uf_partial->pt_ectx_stack;
268cd45ed03SBram Moolenaar 	ectx->ec_outer_frame = ufunc->uf_partial->pt_ectx_frame;
269cd45ed03SBram Moolenaar     }
270cd45ed03SBram Moolenaar 
2718a7d6542SBram Moolenaar     // Set execution state to the start of the called function.
2728a7d6542SBram Moolenaar     ectx->ec_dfunc_idx = cdf_idx;
2738a7d6542SBram Moolenaar     ectx->ec_instr = dfunc->df_instr;
274c620c055SBram Moolenaar     entry = estack_push_ufunc(dfunc->df_ufunc, 1);
275c620c055SBram Moolenaar     if (entry != NULL)
276c620c055SBram Moolenaar     {
277c620c055SBram Moolenaar 	// Set the script context to the script where the function was defined.
278c620c055SBram Moolenaar 	// TODO: save more than the SID?
279c620c055SBram Moolenaar 	entry->es_save_sid = current_sctx.sc_sid;
280c620c055SBram Moolenaar 	current_sctx.sc_sid = ufunc->uf_script_ctx.sc_sid;
281c620c055SBram Moolenaar     }
282170fcfcfSBram Moolenaar 
283170fcfcfSBram Moolenaar     // Decide where to start execution, handles optional arguments.
284170fcfcfSBram Moolenaar     init_instr_idx(ufunc, argcount, ectx);
2858a7d6542SBram Moolenaar 
2868a7d6542SBram Moolenaar     return OK;
2878a7d6542SBram Moolenaar }
2888a7d6542SBram Moolenaar 
2898a7d6542SBram Moolenaar // Get pointer to item in the stack.
2908a7d6542SBram Moolenaar #define STACK_TV(idx) (((typval_T *)ectx->ec_stack.ga_data) + idx)
2918a7d6542SBram Moolenaar 
2928a7d6542SBram Moolenaar /*
293bf67ea1aSBram Moolenaar  * Used when returning from a function: Check if any closure is still
294bf67ea1aSBram Moolenaar  * referenced.  If so then move the arguments and variables to a separate piece
295bf67ea1aSBram Moolenaar  * of stack to be used when the closure is called.
296bf67ea1aSBram Moolenaar  * When "free_arguments" is TRUE the arguments are to be freed.
297bf67ea1aSBram Moolenaar  * Returns FAIL when out of memory.
298bf67ea1aSBram Moolenaar  */
299bf67ea1aSBram Moolenaar     static int
300bf67ea1aSBram Moolenaar handle_closure_in_use(ectx_T *ectx, int free_arguments)
301bf67ea1aSBram Moolenaar {
302bf67ea1aSBram Moolenaar     dfunc_T	*dfunc = ((dfunc_T *)def_functions.ga_data)
303bf67ea1aSBram Moolenaar 							  + ectx->ec_dfunc_idx;
304fdeab65dSBram Moolenaar     int		argcount;
305fdeab65dSBram Moolenaar     int		top;
306bf67ea1aSBram Moolenaar     int		idx;
307bf67ea1aSBram Moolenaar     typval_T	*tv;
308bf67ea1aSBram Moolenaar     int		closure_in_use = FALSE;
309148ce7aeSBram Moolenaar     garray_T	*gap = &ectx->ec_funcrefs;
310148ce7aeSBram Moolenaar     varnumber_T	closure_count;
311bf67ea1aSBram Moolenaar 
312fdeab65dSBram Moolenaar     if (dfunc->df_ufunc == NULL)
313148ce7aeSBram Moolenaar 	return OK;  // function was freed
314148ce7aeSBram Moolenaar     if (dfunc->df_has_closure == 0)
315148ce7aeSBram Moolenaar 	return OK;  // no closures
316148ce7aeSBram Moolenaar     tv = STACK_TV(ectx->ec_frame_idx + STACK_FRAME_SIZE + dfunc->df_varcount);
317148ce7aeSBram Moolenaar     closure_count = tv->vval.v_number;
318148ce7aeSBram Moolenaar     if (closure_count == 0)
319148ce7aeSBram Moolenaar 	return OK;  // no funcrefs created
320148ce7aeSBram Moolenaar 
321fdeab65dSBram Moolenaar     argcount = ufunc_argcount(dfunc->df_ufunc);
322fdeab65dSBram Moolenaar     top = ectx->ec_frame_idx - argcount;
323fdeab65dSBram Moolenaar 
324bf67ea1aSBram Moolenaar     // Check if any created closure is still in use.
325148ce7aeSBram Moolenaar     for (idx = 0; idx < closure_count; ++idx)
326bf67ea1aSBram Moolenaar     {
327c70bdab0SBram Moolenaar 	partial_T   *pt;
328c70bdab0SBram Moolenaar 	int	    off = gap->ga_len - closure_count + idx;
329148ce7aeSBram Moolenaar 
330c70bdab0SBram Moolenaar 	if (off < 0)
331c70bdab0SBram Moolenaar 	    continue;  // count is off or already done
332c70bdab0SBram Moolenaar 	pt = ((partial_T **)gap->ga_data)[off];
333148ce7aeSBram Moolenaar 	if (pt->pt_refcount > 1)
334221fcc74SBram Moolenaar 	{
335148ce7aeSBram Moolenaar 	    int refcount = pt->pt_refcount;
336221fcc74SBram Moolenaar 	    int i;
337221fcc74SBram Moolenaar 
338f821ddaaSBram Moolenaar 	    // A Reference in a local variables doesn't count, it gets
339221fcc74SBram Moolenaar 	    // unreferenced on return.
340221fcc74SBram Moolenaar 	    for (i = 0; i < dfunc->df_varcount; ++i)
341221fcc74SBram Moolenaar 	    {
342221fcc74SBram Moolenaar 		typval_T *stv = STACK_TV(ectx->ec_frame_idx
343221fcc74SBram Moolenaar 						       + STACK_FRAME_SIZE + i);
344148ce7aeSBram Moolenaar 		if (stv->v_type == VAR_PARTIAL && pt == stv->vval.v_partial)
345221fcc74SBram Moolenaar 		    --refcount;
346221fcc74SBram Moolenaar 	    }
347221fcc74SBram Moolenaar 	    if (refcount > 1)
348f7779c63SBram Moolenaar 	    {
349bf67ea1aSBram Moolenaar 		closure_in_use = TRUE;
350f7779c63SBram Moolenaar 		break;
351f7779c63SBram Moolenaar 	    }
352bf67ea1aSBram Moolenaar 	}
353221fcc74SBram Moolenaar     }
354bf67ea1aSBram Moolenaar 
355bf67ea1aSBram Moolenaar     if (closure_in_use)
356bf67ea1aSBram Moolenaar     {
357bf67ea1aSBram Moolenaar 	funcstack_T *funcstack = ALLOC_CLEAR_ONE(funcstack_T);
358bf67ea1aSBram Moolenaar 	typval_T    *stack;
359bf67ea1aSBram Moolenaar 
360bf67ea1aSBram Moolenaar 	// A closure is using the arguments and/or local variables.
361bf67ea1aSBram Moolenaar 	// Move them to the called function.
362bf67ea1aSBram Moolenaar 	if (funcstack == NULL)
363bf67ea1aSBram Moolenaar 	    return FAIL;
36485d5e2b7SBram Moolenaar 	funcstack->fs_var_offset = argcount + STACK_FRAME_SIZE;
36585d5e2b7SBram Moolenaar 	funcstack->fs_ga.ga_len = funcstack->fs_var_offset + dfunc->df_varcount;
366bf67ea1aSBram Moolenaar 	stack = ALLOC_CLEAR_MULT(typval_T, funcstack->fs_ga.ga_len);
367bf67ea1aSBram Moolenaar 	funcstack->fs_ga.ga_data = stack;
368bf67ea1aSBram Moolenaar 	if (stack == NULL)
369bf67ea1aSBram Moolenaar 	{
370bf67ea1aSBram Moolenaar 	    vim_free(funcstack);
371bf67ea1aSBram Moolenaar 	    return FAIL;
372bf67ea1aSBram Moolenaar 	}
373bf67ea1aSBram Moolenaar 
374bf67ea1aSBram Moolenaar 	// Move or copy the arguments.
375bf67ea1aSBram Moolenaar 	for (idx = 0; idx < argcount; ++idx)
376bf67ea1aSBram Moolenaar 	{
377bf67ea1aSBram Moolenaar 	    tv = STACK_TV(top + idx);
378bf67ea1aSBram Moolenaar 	    if (free_arguments)
379bf67ea1aSBram Moolenaar 	    {
380bf67ea1aSBram Moolenaar 		*(stack + idx) = *tv;
381bf67ea1aSBram Moolenaar 		tv->v_type = VAR_UNKNOWN;
382bf67ea1aSBram Moolenaar 	    }
383bf67ea1aSBram Moolenaar 	    else
384bf67ea1aSBram Moolenaar 		copy_tv(tv, stack + idx);
385bf67ea1aSBram Moolenaar 	}
386bf67ea1aSBram Moolenaar 	// Move the local variables.
387bf67ea1aSBram Moolenaar 	for (idx = 0; idx < dfunc->df_varcount; ++idx)
388bf67ea1aSBram Moolenaar 	{
389bf67ea1aSBram Moolenaar 	    tv = STACK_TV(ectx->ec_frame_idx + STACK_FRAME_SIZE + idx);
390f821ddaaSBram Moolenaar 
39185d5e2b7SBram Moolenaar 	    // A partial created for a local function, that is also used as a
39285d5e2b7SBram Moolenaar 	    // local variable, has a reference count for the variable, thus
39385d5e2b7SBram Moolenaar 	    // will never go down to zero.  When all these refcounts are one
39485d5e2b7SBram Moolenaar 	    // then the funcstack is unused.  We need to count how many we have
39585d5e2b7SBram Moolenaar 	    // so we need when to check.
396f821ddaaSBram Moolenaar 	    if (tv->v_type == VAR_PARTIAL && tv->vval.v_partial != NULL)
397f821ddaaSBram Moolenaar 	    {
398f821ddaaSBram Moolenaar 		int	    i;
399f821ddaaSBram Moolenaar 
400148ce7aeSBram Moolenaar 		for (i = 0; i < closure_count; ++i)
40185d5e2b7SBram Moolenaar 		    if (tv->vval.v_partial == ((partial_T **)gap->ga_data)[
40285d5e2b7SBram Moolenaar 					      gap->ga_len - closure_count + i])
40385d5e2b7SBram Moolenaar 			++funcstack->fs_min_refcount;
404f821ddaaSBram Moolenaar 	    }
405f821ddaaSBram Moolenaar 
40685d5e2b7SBram Moolenaar 	    *(stack + funcstack->fs_var_offset + idx) = *tv;
407bf67ea1aSBram Moolenaar 	    tv->v_type = VAR_UNKNOWN;
408bf67ea1aSBram Moolenaar 	}
409bf67ea1aSBram Moolenaar 
410148ce7aeSBram Moolenaar 	for (idx = 0; idx < closure_count; ++idx)
411bf67ea1aSBram Moolenaar 	{
412148ce7aeSBram Moolenaar 	    partial_T *pt = ((partial_T **)gap->ga_data)[gap->ga_len
413148ce7aeSBram Moolenaar 							- closure_count + idx];
414148ce7aeSBram Moolenaar 	    if (pt->pt_refcount > 1)
415f7779c63SBram Moolenaar 	    {
416bf67ea1aSBram Moolenaar 		++funcstack->fs_refcount;
417148ce7aeSBram Moolenaar 		pt->pt_funcstack = funcstack;
418148ce7aeSBram Moolenaar 		pt->pt_ectx_stack = &funcstack->fs_ga;
419148ce7aeSBram Moolenaar 		pt->pt_ectx_frame = ectx->ec_frame_idx - top;
420f7779c63SBram Moolenaar 	    }
421bf67ea1aSBram Moolenaar 	}
422bf67ea1aSBram Moolenaar     }
423148ce7aeSBram Moolenaar 
424148ce7aeSBram Moolenaar     for (idx = 0; idx < closure_count; ++idx)
425148ce7aeSBram Moolenaar 	partial_unref(((partial_T **)gap->ga_data)[gap->ga_len
426148ce7aeSBram Moolenaar 						       - closure_count + idx]);
427148ce7aeSBram Moolenaar     gap->ga_len -= closure_count;
428148ce7aeSBram Moolenaar     if (gap->ga_len == 0)
429148ce7aeSBram Moolenaar 	ga_clear(gap);
430bf67ea1aSBram Moolenaar 
431bf67ea1aSBram Moolenaar     return OK;
432bf67ea1aSBram Moolenaar }
433bf67ea1aSBram Moolenaar 
434bf67ea1aSBram Moolenaar /*
43585d5e2b7SBram Moolenaar  * Called when a partial is freed or its reference count goes down to one.  The
43685d5e2b7SBram Moolenaar  * funcstack may be the only reference to the partials in the local variables.
43785d5e2b7SBram Moolenaar  * Go over all of them, the funcref and can be freed if all partials
43885d5e2b7SBram Moolenaar  * referencing the funcstack have a reference count of one.
43985d5e2b7SBram Moolenaar  */
44085d5e2b7SBram Moolenaar     void
44185d5e2b7SBram Moolenaar funcstack_check_refcount(funcstack_T *funcstack)
44285d5e2b7SBram Moolenaar {
44385d5e2b7SBram Moolenaar     int		    i;
44485d5e2b7SBram Moolenaar     garray_T	    *gap = &funcstack->fs_ga;
44585d5e2b7SBram Moolenaar     int		    done = 0;
44685d5e2b7SBram Moolenaar 
44785d5e2b7SBram Moolenaar     if (funcstack->fs_refcount > funcstack->fs_min_refcount)
44885d5e2b7SBram Moolenaar 	return;
44985d5e2b7SBram Moolenaar     for (i = funcstack->fs_var_offset; i < gap->ga_len; ++i)
45085d5e2b7SBram Moolenaar     {
45185d5e2b7SBram Moolenaar 	typval_T *tv = ((typval_T *)gap->ga_data) + i;
45285d5e2b7SBram Moolenaar 
45385d5e2b7SBram Moolenaar 	if (tv->v_type == VAR_PARTIAL && tv->vval.v_partial != NULL
45485d5e2b7SBram Moolenaar 		&& tv->vval.v_partial->pt_funcstack == funcstack
45585d5e2b7SBram Moolenaar 		&& tv->vval.v_partial->pt_refcount == 1)
45685d5e2b7SBram Moolenaar 	    ++done;
45785d5e2b7SBram Moolenaar     }
45885d5e2b7SBram Moolenaar     if (done == funcstack->fs_min_refcount)
45985d5e2b7SBram Moolenaar     {
46085d5e2b7SBram Moolenaar 	typval_T	*stack = gap->ga_data;
46185d5e2b7SBram Moolenaar 
46285d5e2b7SBram Moolenaar 	// All partials referencing the funcstack have a reference count of
46385d5e2b7SBram Moolenaar 	// one, thus the funcstack is no longer of use.
46485d5e2b7SBram Moolenaar 	for (i = 0; i < gap->ga_len; ++i)
46585d5e2b7SBram Moolenaar 	    clear_tv(stack + i);
46685d5e2b7SBram Moolenaar 	vim_free(stack);
46785d5e2b7SBram Moolenaar 	vim_free(funcstack);
46885d5e2b7SBram Moolenaar     }
46985d5e2b7SBram Moolenaar }
47085d5e2b7SBram Moolenaar 
47185d5e2b7SBram Moolenaar /*
4728a7d6542SBram Moolenaar  * Return from the current function.
4738a7d6542SBram Moolenaar  */
474bf67ea1aSBram Moolenaar     static int
4758a7d6542SBram Moolenaar func_return(ectx_T *ectx)
4768a7d6542SBram Moolenaar {
4778a7d6542SBram Moolenaar     int		idx;
47834c54eb6SBram Moolenaar     int		ret_idx;
479bf67ea1aSBram Moolenaar     dfunc_T	*dfunc = ((dfunc_T *)def_functions.ga_data)
480bf67ea1aSBram Moolenaar 							  + ectx->ec_dfunc_idx;
481bf67ea1aSBram Moolenaar     int		argcount = ufunc_argcount(dfunc->df_ufunc);
482bf67ea1aSBram Moolenaar     int		top = ectx->ec_frame_idx - argcount;
483c620c055SBram Moolenaar     estack_T	*entry;
4848a7d6542SBram Moolenaar 
4858a7d6542SBram Moolenaar     // execution context goes one level up
486c620c055SBram Moolenaar     entry = estack_pop();
487c620c055SBram Moolenaar     if (entry != NULL)
488c620c055SBram Moolenaar 	current_sctx.sc_sid = entry->es_save_sid;
4898a7d6542SBram Moolenaar 
490bf67ea1aSBram Moolenaar     if (handle_closure_in_use(ectx, TRUE) == FAIL)
491bf67ea1aSBram Moolenaar 	return FAIL;
492bf67ea1aSBram Moolenaar 
493bf67ea1aSBram Moolenaar     // Clear the arguments.
494bf67ea1aSBram Moolenaar     for (idx = top; idx < ectx->ec_frame_idx; ++idx)
495bf67ea1aSBram Moolenaar 	clear_tv(STACK_TV(idx));
496bf67ea1aSBram Moolenaar 
497bf67ea1aSBram Moolenaar     // Clear local variables and temp values, but not the return value.
498bf67ea1aSBram Moolenaar     for (idx = ectx->ec_frame_idx + STACK_FRAME_SIZE;
4998a7d6542SBram Moolenaar 					idx < ectx->ec_stack.ga_len - 1; ++idx)
5008a7d6542SBram Moolenaar 	clear_tv(STACK_TV(idx));
501170fcfcfSBram Moolenaar 
50234c54eb6SBram Moolenaar     // The return value should be on top of the stack.  However, when aborting
50334c54eb6SBram Moolenaar     // it may not be there and ec_frame_idx is the top of the stack.
50434c54eb6SBram Moolenaar     ret_idx = ectx->ec_stack.ga_len - 1;
50534c54eb6SBram Moolenaar     if (ret_idx == ectx->ec_frame_idx + 4)
50634c54eb6SBram Moolenaar 	ret_idx = 0;
50734c54eb6SBram Moolenaar 
508170fcfcfSBram Moolenaar     // Restore the previous frame.
509bf67ea1aSBram Moolenaar     ectx->ec_dfunc_idx = STACK_TV(ectx->ec_frame_idx)->vval.v_number;
510bf67ea1aSBram Moolenaar     ectx->ec_iidx = STACK_TV(ectx->ec_frame_idx + 1)->vval.v_number;
5115366e1aeSBram Moolenaar     ectx->ec_outer_stack =
5125366e1aeSBram Moolenaar 		       (void *)STACK_TV(ectx->ec_frame_idx + 2)->vval.v_string;
5135366e1aeSBram Moolenaar     ectx->ec_outer_frame = STACK_TV(ectx->ec_frame_idx + 3)->vval.v_number;
5145366e1aeSBram Moolenaar     // restoring ec_frame_idx must be last
5155366e1aeSBram Moolenaar     ectx->ec_frame_idx = STACK_TV(ectx->ec_frame_idx + 4)->vval.v_number;
5168a7d6542SBram Moolenaar     dfunc = ((dfunc_T *)def_functions.ga_data) + ectx->ec_dfunc_idx;
5178a7d6542SBram Moolenaar     ectx->ec_instr = dfunc->df_instr;
518170fcfcfSBram Moolenaar 
51934c54eb6SBram Moolenaar     if (ret_idx > 0)
52034c54eb6SBram Moolenaar     {
52134c54eb6SBram Moolenaar 	// Reset the stack to the position before the call, with a spot for the
52234c54eb6SBram Moolenaar 	// return value, moved there from above the frame.
523170fcfcfSBram Moolenaar 	ectx->ec_stack.ga_len = top + 1;
52434c54eb6SBram Moolenaar 	*STACK_TV_BOT(-1) = *STACK_TV(ret_idx);
52534c54eb6SBram Moolenaar     }
52634c54eb6SBram Moolenaar     else
52734c54eb6SBram Moolenaar 	// Reset the stack to the position before the call.
52834c54eb6SBram Moolenaar 	ectx->ec_stack.ga_len = top;
529bf67ea1aSBram Moolenaar 
5300ba48e8cSBram Moolenaar     funcdepth_decrement();
531bf67ea1aSBram Moolenaar     return OK;
5328a7d6542SBram Moolenaar }
5338a7d6542SBram Moolenaar 
5348a7d6542SBram Moolenaar #undef STACK_TV
5358a7d6542SBram Moolenaar 
5368a7d6542SBram Moolenaar /*
5378a7d6542SBram Moolenaar  * Prepare arguments and rettv for calling a builtin or user function.
5388a7d6542SBram Moolenaar  */
5398a7d6542SBram Moolenaar     static int
5408a7d6542SBram Moolenaar call_prepare(int argcount, typval_T *argvars, ectx_T *ectx)
5418a7d6542SBram Moolenaar {
5428a7d6542SBram Moolenaar     int		idx;
5438a7d6542SBram Moolenaar     typval_T	*tv;
5448a7d6542SBram Moolenaar 
5458a7d6542SBram Moolenaar     // Move arguments from bottom of the stack to argvars[] and add terminator.
5468a7d6542SBram Moolenaar     for (idx = 0; idx < argcount; ++idx)
5478a7d6542SBram Moolenaar 	argvars[idx] = *STACK_TV_BOT(idx - argcount);
5488a7d6542SBram Moolenaar     argvars[argcount].v_type = VAR_UNKNOWN;
5498a7d6542SBram Moolenaar 
5508a7d6542SBram Moolenaar     // Result replaces the arguments on the stack.
5518a7d6542SBram Moolenaar     if (argcount > 0)
5528a7d6542SBram Moolenaar 	ectx->ec_stack.ga_len -= argcount - 1;
553270d0388SBram Moolenaar     else if (GA_GROW(&ectx->ec_stack, 1) == FAIL)
5548a7d6542SBram Moolenaar 	return FAIL;
5558a7d6542SBram Moolenaar     else
5568a7d6542SBram Moolenaar 	++ectx->ec_stack.ga_len;
5578a7d6542SBram Moolenaar 
5588a7d6542SBram Moolenaar     // Default return value is zero.
5598a7d6542SBram Moolenaar     tv = STACK_TV_BOT(-1);
5608a7d6542SBram Moolenaar     tv->v_type = VAR_NUMBER;
5618a7d6542SBram Moolenaar     tv->vval.v_number = 0;
5628a7d6542SBram Moolenaar 
5638a7d6542SBram Moolenaar     return OK;
5648a7d6542SBram Moolenaar }
5658a7d6542SBram Moolenaar 
56608f7a41bSBram Moolenaar // Ugly global to avoid passing the execution context around through many
56708f7a41bSBram Moolenaar // layers.
56808f7a41bSBram Moolenaar static ectx_T *current_ectx = NULL;
56908f7a41bSBram Moolenaar 
5708a7d6542SBram Moolenaar /*
5718a7d6542SBram Moolenaar  * Call a builtin function by index.
5728a7d6542SBram Moolenaar  */
5738a7d6542SBram Moolenaar     static int
5748a7d6542SBram Moolenaar call_bfunc(int func_idx, int argcount, ectx_T *ectx)
5758a7d6542SBram Moolenaar {
5768a7d6542SBram Moolenaar     typval_T	argvars[MAX_FUNC_ARGS];
5778a7d6542SBram Moolenaar     int		idx;
578171fb923SBram Moolenaar     int		did_emsg_before = did_emsg;
57908f7a41bSBram Moolenaar     ectx_T	*prev_ectx = current_ectx;
5808a7d6542SBram Moolenaar 
5818a7d6542SBram Moolenaar     if (call_prepare(argcount, argvars, ectx) == FAIL)
5828a7d6542SBram Moolenaar 	return FAIL;
5838a7d6542SBram Moolenaar 
58408f7a41bSBram Moolenaar     // Call the builtin function.  Set "current_ectx" so that when it
58508f7a41bSBram Moolenaar     // recursively invokes call_def_function() a closure context can be set.
58608f7a41bSBram Moolenaar     current_ectx = ectx;
5878a7d6542SBram Moolenaar     call_internal_func_by_idx(func_idx, argvars, STACK_TV_BOT(-1));
58808f7a41bSBram Moolenaar     current_ectx = prev_ectx;
5898a7d6542SBram Moolenaar 
5908a7d6542SBram Moolenaar     // Clear the arguments.
5918a7d6542SBram Moolenaar     for (idx = 0; idx < argcount; ++idx)
5928a7d6542SBram Moolenaar 	clear_tv(&argvars[idx]);
593015f4267SBram Moolenaar 
59457f799e6SBram Moolenaar     if (did_emsg > did_emsg_before)
595015f4267SBram Moolenaar 	return FAIL;
5968a7d6542SBram Moolenaar     return OK;
5978a7d6542SBram Moolenaar }
5988a7d6542SBram Moolenaar 
5998a7d6542SBram Moolenaar /*
6008a7d6542SBram Moolenaar  * Execute a user defined function.
6017eeefd4aSBram Moolenaar  * "iptr" can be used to replace the instruction with a more efficient one.
6028a7d6542SBram Moolenaar  */
6038a7d6542SBram Moolenaar     static int
6047eeefd4aSBram Moolenaar call_ufunc(ufunc_T *ufunc, int argcount, ectx_T *ectx, isn_T *iptr)
6058a7d6542SBram Moolenaar {
6068a7d6542SBram Moolenaar     typval_T	argvars[MAX_FUNC_ARGS];
6078a7d6542SBram Moolenaar     funcexe_T   funcexe;
6088a7d6542SBram Moolenaar     int		error;
6098a7d6542SBram Moolenaar     int		idx;
61028ee892aSBram Moolenaar     int		did_emsg_before = did_emsg;
6118a7d6542SBram Moolenaar 
6120cb5bcf5SBram Moolenaar     if (ufunc->uf_def_status == UF_TO_BE_COMPILED
613822ba247SBram Moolenaar 	    && compile_def_function(ufunc, FALSE, NULL) == FAIL)
614822ba247SBram Moolenaar 	return FAIL;
6150cb5bcf5SBram Moolenaar     if (ufunc->uf_def_status == UF_COMPILED)
6167eeefd4aSBram Moolenaar     {
61752c124d3SBram Moolenaar 	error = check_user_func_argcount(ufunc, argcount);
6185082471fSBram Moolenaar 	if (error != FCERR_UNKNOWN)
6195082471fSBram Moolenaar 	{
6205082471fSBram Moolenaar 	    if (error == FCERR_TOOMANY)
6215082471fSBram Moolenaar 		semsg(_(e_toomanyarg), ufunc->uf_name);
6225082471fSBram Moolenaar 	    else
6235082471fSBram Moolenaar 		semsg(_(e_toofewarg), ufunc->uf_name);
6245082471fSBram Moolenaar 	    return FAIL;
6255082471fSBram Moolenaar 	}
6265082471fSBram Moolenaar 
6277eeefd4aSBram Moolenaar 	// The function has been compiled, can call it quickly.  For a function
6287eeefd4aSBram Moolenaar 	// that was defined later: we can call it directly next time.
629cd45ed03SBram Moolenaar 	// TODO: what if the function was deleted and then defined again?
6307eeefd4aSBram Moolenaar 	if (iptr != NULL)
6317eeefd4aSBram Moolenaar 	{
63220431c9dSBram Moolenaar 	    delete_instr(iptr);
6337eeefd4aSBram Moolenaar 	    iptr->isn_type = ISN_DCALL;
6347eeefd4aSBram Moolenaar 	    iptr->isn_arg.dfunc.cdf_idx = ufunc->uf_dfunc_idx;
6357eeefd4aSBram Moolenaar 	    iptr->isn_arg.dfunc.cdf_argcount = argcount;
6367eeefd4aSBram Moolenaar 	}
6378a7d6542SBram Moolenaar 	return call_dfunc(ufunc->uf_dfunc_idx, argcount, ectx);
6387eeefd4aSBram Moolenaar     }
6398a7d6542SBram Moolenaar 
6408a7d6542SBram Moolenaar     if (call_prepare(argcount, argvars, ectx) == FAIL)
6418a7d6542SBram Moolenaar 	return FAIL;
642a80faa89SBram Moolenaar     CLEAR_FIELD(funcexe);
6438a7d6542SBram Moolenaar     funcexe.evaluate = TRUE;
6448a7d6542SBram Moolenaar 
6458a7d6542SBram Moolenaar     // Call the user function.  Result goes in last position on the stack.
6468a7d6542SBram Moolenaar     // TODO: add selfdict if there is one
6478a7d6542SBram Moolenaar     error = call_user_func_check(ufunc, argcount, argvars,
6488a7d6542SBram Moolenaar 					     STACK_TV_BOT(-1), &funcexe, NULL);
6498a7d6542SBram Moolenaar 
6508a7d6542SBram Moolenaar     // Clear the arguments.
6518a7d6542SBram Moolenaar     for (idx = 0; idx < argcount; ++idx)
6528a7d6542SBram Moolenaar 	clear_tv(&argvars[idx]);
6538a7d6542SBram Moolenaar 
6548a7d6542SBram Moolenaar     if (error != FCERR_NONE)
6558a7d6542SBram Moolenaar     {
6568a7d6542SBram Moolenaar 	user_func_error(error, ufunc->uf_name);
6578a7d6542SBram Moolenaar 	return FAIL;
6588a7d6542SBram Moolenaar     }
65928ee892aSBram Moolenaar     if (did_emsg > did_emsg_before)
660ed677f55SBram Moolenaar 	// Error other than from calling the function itself.
661ed677f55SBram Moolenaar 	return FAIL;
6628a7d6542SBram Moolenaar     return OK;
6638a7d6542SBram Moolenaar }
6648a7d6542SBram Moolenaar 
6658a7d6542SBram Moolenaar /*
666a177344dSBram Moolenaar  * Return TRUE if an error was given or CTRL-C was pressed.
667a177344dSBram Moolenaar  */
668a177344dSBram Moolenaar     static int
669a177344dSBram Moolenaar vim9_aborting(int prev_called_emsg)
670a177344dSBram Moolenaar {
671a177344dSBram Moolenaar     return called_emsg > prev_called_emsg || got_int || did_throw;
672a177344dSBram Moolenaar }
673a177344dSBram Moolenaar 
674a177344dSBram Moolenaar /*
6758a7d6542SBram Moolenaar  * Execute a function by "name".
6768a7d6542SBram Moolenaar  * This can be a builtin function or a user function.
6777eeefd4aSBram Moolenaar  * "iptr" can be used to replace the instruction with a more efficient one.
6788a7d6542SBram Moolenaar  * Returns FAIL if not found without an error message.
6798a7d6542SBram Moolenaar  */
6808a7d6542SBram Moolenaar     static int
6817eeefd4aSBram Moolenaar call_by_name(char_u *name, int argcount, ectx_T *ectx, isn_T *iptr)
6828a7d6542SBram Moolenaar {
6838a7d6542SBram Moolenaar     ufunc_T *ufunc;
6848a7d6542SBram Moolenaar 
6858a7d6542SBram Moolenaar     if (builtin_function(name, -1))
6868a7d6542SBram Moolenaar     {
6878a7d6542SBram Moolenaar 	int func_idx = find_internal_func(name);
6888a7d6542SBram Moolenaar 
6898a7d6542SBram Moolenaar 	if (func_idx < 0)
6908a7d6542SBram Moolenaar 	    return FAIL;
691389df259SBram Moolenaar 	if (check_internal_func(func_idx, argcount) < 0)
6928a7d6542SBram Moolenaar 	    return FAIL;
6938a7d6542SBram Moolenaar 	return call_bfunc(func_idx, argcount, ectx);
6948a7d6542SBram Moolenaar     }
6958a7d6542SBram Moolenaar 
6964c17ad94SBram Moolenaar     ufunc = find_func(name, FALSE, NULL);
697a177344dSBram Moolenaar 
698a177344dSBram Moolenaar     if (ufunc == NULL)
699a177344dSBram Moolenaar     {
700a177344dSBram Moolenaar 	int called_emsg_before = called_emsg;
701a177344dSBram Moolenaar 
702a177344dSBram Moolenaar 	if (script_autoload(name, TRUE))
703a177344dSBram Moolenaar 	    // loaded a package, search for the function again
704a177344dSBram Moolenaar 	    ufunc = find_func(name, FALSE, NULL);
705a177344dSBram Moolenaar 	if (vim9_aborting(called_emsg_before))
706a177344dSBram Moolenaar 	    return FAIL;  // bail out if loading the script caused an error
707a177344dSBram Moolenaar     }
708a177344dSBram Moolenaar 
7098a7d6542SBram Moolenaar     if (ufunc != NULL)
7107eeefd4aSBram Moolenaar 	return call_ufunc(ufunc, argcount, ectx, iptr);
7118a7d6542SBram Moolenaar 
7128a7d6542SBram Moolenaar     return FAIL;
7138a7d6542SBram Moolenaar }
7148a7d6542SBram Moolenaar 
7158a7d6542SBram Moolenaar     static int
716a90afb9aSBram Moolenaar call_partial(typval_T *tv, int argcount_arg, ectx_T *ectx)
7178a7d6542SBram Moolenaar {
718a90afb9aSBram Moolenaar     int		argcount = argcount_arg;
719bd5da371SBram Moolenaar     char_u	*name = NULL;
7208a7d6542SBram Moolenaar     int		called_emsg_before = called_emsg;
72195006e3dSBram Moolenaar     int		res;
7228a7d6542SBram Moolenaar 
7238a7d6542SBram Moolenaar     if (tv->v_type == VAR_PARTIAL)
7248a7d6542SBram Moolenaar     {
7258a7d6542SBram Moolenaar 	partial_T   *pt = tv->vval.v_partial;
726a90afb9aSBram Moolenaar 	int	    i;
727a90afb9aSBram Moolenaar 
728a90afb9aSBram Moolenaar 	if (pt->pt_argc > 0)
729a90afb9aSBram Moolenaar 	{
730a90afb9aSBram Moolenaar 	    // Make space for arguments from the partial, shift the "argcount"
731a90afb9aSBram Moolenaar 	    // arguments up.
732a90afb9aSBram Moolenaar 	    if (ga_grow(&ectx->ec_stack, pt->pt_argc) == FAIL)
733a90afb9aSBram Moolenaar 		return FAIL;
734a90afb9aSBram Moolenaar 	    for (i = 1; i <= argcount; ++i)
735a90afb9aSBram Moolenaar 		*STACK_TV_BOT(-i + pt->pt_argc) = *STACK_TV_BOT(-i);
736a90afb9aSBram Moolenaar 	    ectx->ec_stack.ga_len += pt->pt_argc;
737a90afb9aSBram Moolenaar 	    argcount += pt->pt_argc;
738a90afb9aSBram Moolenaar 
739a90afb9aSBram Moolenaar 	    // copy the arguments from the partial onto the stack
740a90afb9aSBram Moolenaar 	    for (i = 0; i < pt->pt_argc; ++i)
741a90afb9aSBram Moolenaar 		copy_tv(&pt->pt_argv[i], STACK_TV_BOT(-argcount + i));
742a90afb9aSBram Moolenaar 	}
7438a7d6542SBram Moolenaar 
7448a7d6542SBram Moolenaar 	if (pt->pt_func != NULL)
745f7779c63SBram Moolenaar 	{
746f7779c63SBram Moolenaar 	    int ret = call_ufunc(pt->pt_func, argcount, ectx, NULL);
747f7779c63SBram Moolenaar 
748f7779c63SBram Moolenaar 	    // closure may need the function context where it was defined
749f7779c63SBram Moolenaar 	    ectx->ec_outer_stack = pt->pt_ectx_stack;
750f7779c63SBram Moolenaar 	    ectx->ec_outer_frame = pt->pt_ectx_frame;
751f7779c63SBram Moolenaar 
752f7779c63SBram Moolenaar 	    return ret;
753f7779c63SBram Moolenaar 	}
7548a7d6542SBram Moolenaar 	name = pt->pt_name;
7558a7d6542SBram Moolenaar     }
756bd5da371SBram Moolenaar     else if (tv->v_type == VAR_FUNC)
7578a7d6542SBram Moolenaar 	name = tv->vval.v_string;
75895006e3dSBram Moolenaar     if (name != NULL)
75995006e3dSBram Moolenaar     {
76095006e3dSBram Moolenaar 	char_u	fname_buf[FLEN_FIXED + 1];
76195006e3dSBram Moolenaar 	char_u	*tofree = NULL;
76295006e3dSBram Moolenaar 	int	error = FCERR_NONE;
76395006e3dSBram Moolenaar 	char_u	*fname;
76495006e3dSBram Moolenaar 
76595006e3dSBram Moolenaar 	// May need to translate <SNR>123_ to K_SNR.
76695006e3dSBram Moolenaar 	fname = fname_trans_sid(name, fname_buf, &tofree, &error);
76795006e3dSBram Moolenaar 	if (error != FCERR_NONE)
76895006e3dSBram Moolenaar 	    res = FAIL;
76995006e3dSBram Moolenaar 	else
77095006e3dSBram Moolenaar 	    res = call_by_name(fname, argcount, ectx, NULL);
77195006e3dSBram Moolenaar 	vim_free(tofree);
77295006e3dSBram Moolenaar     }
77395006e3dSBram Moolenaar 
77495006e3dSBram Moolenaar     if (name == NULL || res == FAIL)
7758a7d6542SBram Moolenaar     {
7768a7d6542SBram Moolenaar 	if (called_emsg == called_emsg_before)
777015f4267SBram Moolenaar 	    semsg(_(e_unknownfunc),
778015f4267SBram Moolenaar 				  name == NULL ? (char_u *)"[unknown]" : name);
7798a7d6542SBram Moolenaar 	return FAIL;
7808a7d6542SBram Moolenaar     }
7818a7d6542SBram Moolenaar     return OK;
7828a7d6542SBram Moolenaar }
7838a7d6542SBram Moolenaar 
7848a7d6542SBram Moolenaar /*
7850b4c66c6SBram Moolenaar  * Check if "lock" is VAR_LOCKED or VAR_FIXED.  If so give an error and return
7860b4c66c6SBram Moolenaar  * TRUE.
7870b4c66c6SBram Moolenaar  */
7880b4c66c6SBram Moolenaar     static int
7890b4c66c6SBram Moolenaar error_if_locked(int lock, char *error)
7900b4c66c6SBram Moolenaar {
7910b4c66c6SBram Moolenaar     if (lock & (VAR_LOCKED | VAR_FIXED))
7920b4c66c6SBram Moolenaar     {
7930b4c66c6SBram Moolenaar 	emsg(_(error));
7940b4c66c6SBram Moolenaar 	return TRUE;
7950b4c66c6SBram Moolenaar     }
7960b4c66c6SBram Moolenaar     return FALSE;
7970b4c66c6SBram Moolenaar }
7980b4c66c6SBram Moolenaar 
7990b4c66c6SBram Moolenaar /*
8000bbf722aSBram Moolenaar  * Store "tv" in variable "name".
8010bbf722aSBram Moolenaar  * This is for s: and g: variables.
8020bbf722aSBram Moolenaar  */
8030bbf722aSBram Moolenaar     static void
8040bbf722aSBram Moolenaar store_var(char_u *name, typval_T *tv)
8050bbf722aSBram Moolenaar {
8060bbf722aSBram Moolenaar     funccal_entry_T entry;
8070bbf722aSBram Moolenaar 
8080bbf722aSBram Moolenaar     save_funccal(&entry);
80930fd8204SBram Moolenaar     set_var_const(name, NULL, tv, FALSE, ASSIGN_NO_DECL);
8100bbf722aSBram Moolenaar     restore_funccal();
8110bbf722aSBram Moolenaar }
8120bbf722aSBram Moolenaar 
8133beaf9cdSBram Moolenaar /*
8144f5e3977SBram Moolenaar  * Convert "tv" to a string.
8154f5e3977SBram Moolenaar  * Return FAIL if not allowed.
8164f5e3977SBram Moolenaar  */
8174f5e3977SBram Moolenaar     static int
8184f5e3977SBram Moolenaar do_2string(typval_T *tv, int is_2string_any)
8194f5e3977SBram Moolenaar {
8204f5e3977SBram Moolenaar     if (tv->v_type != VAR_STRING)
8214f5e3977SBram Moolenaar     {
8224f5e3977SBram Moolenaar 	char_u *str;
8234f5e3977SBram Moolenaar 
8244f5e3977SBram Moolenaar 	if (is_2string_any)
8254f5e3977SBram Moolenaar 	{
8264f5e3977SBram Moolenaar 	    switch (tv->v_type)
8274f5e3977SBram Moolenaar 	    {
8284f5e3977SBram Moolenaar 		case VAR_SPECIAL:
8294f5e3977SBram Moolenaar 		case VAR_BOOL:
8304f5e3977SBram Moolenaar 		case VAR_NUMBER:
8314f5e3977SBram Moolenaar 		case VAR_FLOAT:
8324f5e3977SBram Moolenaar 		case VAR_BLOB:	break;
8334f5e3977SBram Moolenaar 		default:	to_string_error(tv->v_type);
8344f5e3977SBram Moolenaar 				return FAIL;
8354f5e3977SBram Moolenaar 	    }
8364f5e3977SBram Moolenaar 	}
8374f5e3977SBram Moolenaar 	str = typval_tostring(tv);
8384f5e3977SBram Moolenaar 	clear_tv(tv);
8394f5e3977SBram Moolenaar 	tv->v_type = VAR_STRING;
8404f5e3977SBram Moolenaar 	tv->vval.v_string = str;
8414f5e3977SBram Moolenaar     }
8424f5e3977SBram Moolenaar     return OK;
8434f5e3977SBram Moolenaar }
8444f5e3977SBram Moolenaar 
8454f5e3977SBram Moolenaar /*
8463beaf9cdSBram Moolenaar  * When the value of "sv" is a null list of dict, allocate it.
8473beaf9cdSBram Moolenaar  */
8483beaf9cdSBram Moolenaar     static void
8493beaf9cdSBram Moolenaar allocate_if_null(typval_T *tv)
8503beaf9cdSBram Moolenaar {
8513beaf9cdSBram Moolenaar     switch (tv->v_type)
8523beaf9cdSBram Moolenaar     {
8533beaf9cdSBram Moolenaar 	case VAR_LIST:
8543beaf9cdSBram Moolenaar 	    if (tv->vval.v_list == NULL)
8553beaf9cdSBram Moolenaar 		rettv_list_alloc(tv);
8563beaf9cdSBram Moolenaar 	    break;
8573beaf9cdSBram Moolenaar 	case VAR_DICT:
8583beaf9cdSBram Moolenaar 	    if (tv->vval.v_dict == NULL)
8593beaf9cdSBram Moolenaar 		rettv_dict_alloc(tv);
8603beaf9cdSBram Moolenaar 	    break;
8613beaf9cdSBram Moolenaar 	default:
8623beaf9cdSBram Moolenaar 	    break;
8633beaf9cdSBram Moolenaar     }
8643beaf9cdSBram Moolenaar }
865d3aac291SBram Moolenaar 
8660bbf722aSBram Moolenaar /*
8678a7d6542SBram Moolenaar  * Execute a function by "name".
8688a7d6542SBram Moolenaar  * This can be a builtin function, user function or a funcref.
8697eeefd4aSBram Moolenaar  * "iptr" can be used to replace the instruction with a more efficient one.
8708a7d6542SBram Moolenaar  */
8718a7d6542SBram Moolenaar     static int
8727eeefd4aSBram Moolenaar call_eval_func(char_u *name, int argcount, ectx_T *ectx, isn_T *iptr)
8738a7d6542SBram Moolenaar {
8748a7d6542SBram Moolenaar     int	    called_emsg_before = called_emsg;
875ed677f55SBram Moolenaar     int	    res;
8768a7d6542SBram Moolenaar 
877ed677f55SBram Moolenaar     res = call_by_name(name, argcount, ectx, iptr);
878ed677f55SBram Moolenaar     if (res == FAIL && called_emsg == called_emsg_before)
8798a7d6542SBram Moolenaar     {
8801df8b3fbSBram Moolenaar 	dictitem_T	*v;
8811df8b3fbSBram Moolenaar 
8821df8b3fbSBram Moolenaar 	v = find_var(name, NULL, FALSE);
8831df8b3fbSBram Moolenaar 	if (v == NULL)
8841df8b3fbSBram Moolenaar 	{
8851df8b3fbSBram Moolenaar 	    semsg(_(e_unknownfunc), name);
8868a7d6542SBram Moolenaar 	    return FAIL;
8878a7d6542SBram Moolenaar 	}
8881df8b3fbSBram Moolenaar 	if (v->di_tv.v_type != VAR_PARTIAL && v->di_tv.v_type != VAR_FUNC)
8891df8b3fbSBram Moolenaar 	{
8901df8b3fbSBram Moolenaar 	    semsg(_(e_unknownfunc), name);
8911df8b3fbSBram Moolenaar 	    return FAIL;
8921df8b3fbSBram Moolenaar 	}
8931df8b3fbSBram Moolenaar 	return call_partial(&v->di_tv, argcount, ectx);
8941df8b3fbSBram Moolenaar     }
895ed677f55SBram Moolenaar     return res;
8968a7d6542SBram Moolenaar }
8978a7d6542SBram Moolenaar 
8988a7d6542SBram Moolenaar /*
899f112f30aSBram Moolenaar  * When a function reference is used, fill a partial with the information
900f112f30aSBram Moolenaar  * needed, especially when it is used as a closure.
901f112f30aSBram Moolenaar  */
902cd45ed03SBram Moolenaar     int
903f112f30aSBram Moolenaar fill_partial_and_closure(partial_T *pt, ufunc_T *ufunc, ectx_T *ectx)
904f112f30aSBram Moolenaar {
905f112f30aSBram Moolenaar     pt->pt_func = ufunc;
906f112f30aSBram Moolenaar     pt->pt_refcount = 1;
907f112f30aSBram Moolenaar 
908f112f30aSBram Moolenaar     if (pt->pt_func->uf_flags & FC_CLOSURE)
909f112f30aSBram Moolenaar     {
910f112f30aSBram Moolenaar 	dfunc_T	*dfunc = ((dfunc_T *)def_functions.ga_data)
911f112f30aSBram Moolenaar 							  + ectx->ec_dfunc_idx;
912f112f30aSBram Moolenaar 
913f112f30aSBram Moolenaar 	// The closure needs to find arguments and local
914f112f30aSBram Moolenaar 	// variables in the current stack.
915f112f30aSBram Moolenaar 	pt->pt_ectx_stack = &ectx->ec_stack;
916f112f30aSBram Moolenaar 	pt->pt_ectx_frame = ectx->ec_frame_idx;
917f112f30aSBram Moolenaar 
918f112f30aSBram Moolenaar 	// If this function returns and the closure is still
919f112f30aSBram Moolenaar 	// being used, we need to make a copy of the context
920f112f30aSBram Moolenaar 	// (arguments and local variables). Store a reference
921f112f30aSBram Moolenaar 	// to the partial so we can handle that.
922f112f30aSBram Moolenaar 	if (ga_grow(&ectx->ec_funcrefs, 1) == FAIL)
923f112f30aSBram Moolenaar 	{
924f112f30aSBram Moolenaar 	    vim_free(pt);
925f112f30aSBram Moolenaar 	    return FAIL;
926f112f30aSBram Moolenaar 	}
927f112f30aSBram Moolenaar 	// Extra variable keeps the count of closures created
928f112f30aSBram Moolenaar 	// in the current function call.
929f112f30aSBram Moolenaar 	++(((typval_T *)ectx->ec_stack.ga_data) + ectx->ec_frame_idx
930f112f30aSBram Moolenaar 		       + STACK_FRAME_SIZE + dfunc->df_varcount)->vval.v_number;
931f112f30aSBram Moolenaar 
932f112f30aSBram Moolenaar 	((partial_T **)ectx->ec_funcrefs.ga_data)
933f112f30aSBram Moolenaar 			       [ectx->ec_funcrefs.ga_len] = pt;
934f112f30aSBram Moolenaar 	++pt->pt_refcount;
935f112f30aSBram Moolenaar 	++ectx->ec_funcrefs.ga_len;
936f112f30aSBram Moolenaar     }
937f112f30aSBram Moolenaar     ++pt->pt_func->uf_refcount;
938f112f30aSBram Moolenaar     return OK;
939f112f30aSBram Moolenaar }
940f112f30aSBram Moolenaar 
941f112f30aSBram Moolenaar /*
9428a7d6542SBram Moolenaar  * Call a "def" function from old Vim script.
9438a7d6542SBram Moolenaar  * Return OK or FAIL.
9448a7d6542SBram Moolenaar  */
9458a7d6542SBram Moolenaar     int
9468a7d6542SBram Moolenaar call_def_function(
9478a7d6542SBram Moolenaar     ufunc_T	*ufunc,
94823e03252SBram Moolenaar     int		argc_arg,	// nr of arguments
9498a7d6542SBram Moolenaar     typval_T	*argv,		// arguments
9506f5b6dfbSBram Moolenaar     partial_T	*partial,	// optional partial for context
9518a7d6542SBram Moolenaar     typval_T	*rettv)		// return value
9528a7d6542SBram Moolenaar {
9538a7d6542SBram Moolenaar     ectx_T	ectx;		// execution context
95423e03252SBram Moolenaar     int		argc = argc_arg;
955bf67ea1aSBram Moolenaar     int		initial_frame_idx;
9568a7d6542SBram Moolenaar     typval_T	*tv;
9578a7d6542SBram Moolenaar     int		idx;
9588a7d6542SBram Moolenaar     int		ret = FAIL;
959170fcfcfSBram Moolenaar     int		defcount = ufunc->uf_args.ga_len - argc;
960ee8580e5SBram Moolenaar     sctx_T	save_current_sctx = current_sctx;
961270d0388SBram Moolenaar     int		breakcheck_count = 0;
962eeece9e4SBram Moolenaar     int		did_emsg_before = did_emsg_cumul + did_emsg;
96377e5dcc3SBram Moolenaar     int		save_suppress_errthrow = suppress_errthrow;
964352134bbSBram Moolenaar     msglist_T	**saved_msg_list = NULL;
965352134bbSBram Moolenaar     msglist_T	*private_msg_list = NULL;
96602194d2bSBram Moolenaar     cmdmod_T	save_cmdmod;
96702194d2bSBram Moolenaar     int		restore_cmdmod = FALSE;
96856602ba1SBram Moolenaar     int		save_emsg_silent_def = emsg_silent_def;
96956602ba1SBram Moolenaar     int		save_did_emsg_def = did_emsg_def;
970171fb923SBram Moolenaar     int		trylevel_at_start = trylevel;
9710ba48e8cSBram Moolenaar     int		orig_funcdepth;
9728a7d6542SBram Moolenaar 
9738a7d6542SBram Moolenaar // Get pointer to item in the stack.
9748a7d6542SBram Moolenaar #define STACK_TV(idx) (((typval_T *)ectx.ec_stack.ga_data) + idx)
9758a7d6542SBram Moolenaar 
9768a7d6542SBram Moolenaar // Get pointer to item at the bottom of the stack, -1 is the bottom.
9778a7d6542SBram Moolenaar #undef STACK_TV_BOT
9788a7d6542SBram Moolenaar #define STACK_TV_BOT(idx) (((typval_T *)ectx.ec_stack.ga_data) + ectx.ec_stack.ga_len + idx)
9798a7d6542SBram Moolenaar 
9801378fbc4SBram Moolenaar // Get pointer to a local variable on the stack.  Negative for arguments.
981bf67ea1aSBram Moolenaar #define STACK_TV_VAR(idx) (((typval_T *)ectx.ec_stack.ga_data) + ectx.ec_frame_idx + STACK_FRAME_SIZE + idx)
9828a7d6542SBram Moolenaar 
983c8cd2b34SBram Moolenaar // Like STACK_TV_VAR but use the outer scope
984c8cd2b34SBram Moolenaar #define STACK_OUT_TV_VAR(idx) (((typval_T *)ectx.ec_outer_stack->ga_data) + ectx.ec_outer_frame + STACK_FRAME_SIZE + idx)
985c8cd2b34SBram Moolenaar 
9860cb5bcf5SBram Moolenaar     if (ufunc->uf_def_status == UF_NOT_COMPILED
9870cb5bcf5SBram Moolenaar 	    || (ufunc->uf_def_status == UF_TO_BE_COMPILED
988822ba247SBram Moolenaar 			  && compile_def_function(ufunc, FALSE, NULL) == FAIL))
98925e0f586SBram Moolenaar     {
990eeece9e4SBram Moolenaar 	if (did_emsg_cumul + did_emsg == did_emsg_before)
991451c2e35SBram Moolenaar 	    semsg(_(e_function_is_not_compiled_str),
992682d0a15SBram Moolenaar 						   printable_func_name(ufunc));
993822ba247SBram Moolenaar 	return FAIL;
99425e0f586SBram Moolenaar     }
995822ba247SBram Moolenaar 
99609689a02SBram Moolenaar     {
997822ba247SBram Moolenaar 	// Check the function was really compiled.
99809689a02SBram Moolenaar 	dfunc_T	*dfunc = ((dfunc_T *)def_functions.ga_data)
99909689a02SBram Moolenaar 							 + ufunc->uf_dfunc_idx;
100009689a02SBram Moolenaar 	if (dfunc->df_instr == NULL)
100138ddf333SBram Moolenaar 	{
100238ddf333SBram Moolenaar 	    iemsg("using call_def_function() on not compiled function");
100309689a02SBram Moolenaar 	    return FAIL;
100409689a02SBram Moolenaar 	}
100538ddf333SBram Moolenaar     }
10068a7d6542SBram Moolenaar 
10070ba48e8cSBram Moolenaar     // If depth of calling is getting too high, don't execute the function.
10080ba48e8cSBram Moolenaar     orig_funcdepth = funcdepth_get();
10090ba48e8cSBram Moolenaar     if (funcdepth_increment() == FAIL)
10100ba48e8cSBram Moolenaar 	return FAIL;
10110ba48e8cSBram Moolenaar 
10123b6a6eb7SBram Moolenaar     CLEAR_FIELD(ectx);
10133b6a6eb7SBram Moolenaar     ectx.ec_dfunc_idx = ufunc->uf_dfunc_idx;
10143b6a6eb7SBram Moolenaar     ga_init2(&ectx.ec_stack, sizeof(typval_T), 500);
10153b6a6eb7SBram Moolenaar     if (ga_grow(&ectx.ec_stack, 20) == FAIL)
10160ba48e8cSBram Moolenaar     {
10170ba48e8cSBram Moolenaar 	funcdepth_decrement();
10183b6a6eb7SBram Moolenaar 	return FAIL;
10190ba48e8cSBram Moolenaar     }
10208a7d6542SBram Moolenaar     ga_init2(&ectx.ec_trystack, sizeof(trycmd_T), 10);
1021148ce7aeSBram Moolenaar     ga_init2(&ectx.ec_funcrefs, sizeof(partial_T *), 10);
10228a7d6542SBram Moolenaar 
1023*fc0e8f5cSBram Moolenaar     // Put arguments on the stack, but no more than what the function expects.
1024*fc0e8f5cSBram Moolenaar     // A lambda can be called with more arguments than it uses.
1025*fc0e8f5cSBram Moolenaar     for (idx = 0; idx < argc
1026*fc0e8f5cSBram Moolenaar 	    && (ufunc->uf_va_name != NULL || idx < ufunc->uf_args.ga_len);
1027*fc0e8f5cSBram Moolenaar 									 ++idx)
10288a7d6542SBram Moolenaar     {
102965b9545fSBram Moolenaar 	if (ufunc->uf_arg_types != NULL && idx < ufunc->uf_args.ga_len
10308b565c2cSBram Moolenaar 		&& check_typval_type(ufunc->uf_arg_types[idx], &argv[idx],
10318b565c2cSBram Moolenaar 							      idx + 1) == FAIL)
103265b9545fSBram Moolenaar 	    goto failed_early;
10338a7d6542SBram Moolenaar 	copy_tv(&argv[idx], STACK_TV_BOT(0));
10348a7d6542SBram Moolenaar 	++ectx.ec_stack.ga_len;
10358a7d6542SBram Moolenaar     }
103623e03252SBram Moolenaar 
103723e03252SBram Moolenaar     // Turn varargs into a list.  Empty list if no args.
103823e03252SBram Moolenaar     if (ufunc->uf_va_name != NULL)
103923e03252SBram Moolenaar     {
104023e03252SBram Moolenaar 	int vararg_count = argc - ufunc->uf_args.ga_len;
104123e03252SBram Moolenaar 
104223e03252SBram Moolenaar 	if (vararg_count < 0)
104323e03252SBram Moolenaar 	    vararg_count = 0;
104423e03252SBram Moolenaar 	else
104523e03252SBram Moolenaar 	    argc -= vararg_count;
104623e03252SBram Moolenaar 	if (exe_newlist(vararg_count, &ectx) == FAIL)
10471a2f4bf6SBram Moolenaar 	    goto failed_early;
104824aa48b7SBram Moolenaar 
104924aa48b7SBram Moolenaar 	// Check the type of the list items.
105024aa48b7SBram Moolenaar 	tv = STACK_TV_BOT(-1);
105124aa48b7SBram Moolenaar 	if (ufunc->uf_va_type != NULL
10522f8cbc4bSBram Moolenaar 		&& ufunc->uf_va_type != &t_any
105324aa48b7SBram Moolenaar 		&& ufunc->uf_va_type->tt_member != &t_any
105424aa48b7SBram Moolenaar 		&& tv->vval.v_list != NULL)
105524aa48b7SBram Moolenaar 	{
105624aa48b7SBram Moolenaar 	    type_T	*expected = ufunc->uf_va_type->tt_member;
105724aa48b7SBram Moolenaar 	    listitem_T	*li = tv->vval.v_list->lv_first;
105824aa48b7SBram Moolenaar 
105924aa48b7SBram Moolenaar 	    for (idx = 0; idx < vararg_count; ++idx)
106024aa48b7SBram Moolenaar 	    {
10618b565c2cSBram Moolenaar 		if (check_typval_type(expected, &li->li_tv,
10628b565c2cSBram Moolenaar 						       argc + idx + 1) == FAIL)
106324aa48b7SBram Moolenaar 		    goto failed_early;
106424aa48b7SBram Moolenaar 		li = li->li_next;
106524aa48b7SBram Moolenaar 	    }
106624aa48b7SBram Moolenaar 	}
106724aa48b7SBram Moolenaar 
106823e03252SBram Moolenaar 	if (defcount > 0)
106923e03252SBram Moolenaar 	    // Move varargs list to below missing default arguments.
107023e03252SBram Moolenaar 	    *STACK_TV_BOT(defcount - 1) = *STACK_TV_BOT(-1);
107123e03252SBram Moolenaar 	--ectx.ec_stack.ga_len;
107223e03252SBram Moolenaar     }
107323e03252SBram Moolenaar 
1074170fcfcfSBram Moolenaar     // Make space for omitted arguments, will store default value below.
107523e03252SBram Moolenaar     // Any varargs list goes after them.
1076170fcfcfSBram Moolenaar     if (defcount > 0)
1077170fcfcfSBram Moolenaar 	for (idx = 0; idx < defcount; ++idx)
1078170fcfcfSBram Moolenaar 	{
1079170fcfcfSBram Moolenaar 	    STACK_TV_BOT(0)->v_type = VAR_UNKNOWN;
1080170fcfcfSBram Moolenaar 	    ++ectx.ec_stack.ga_len;
1081170fcfcfSBram Moolenaar 	}
108223e03252SBram Moolenaar     if (ufunc->uf_va_name != NULL)
108323e03252SBram Moolenaar 	    ++ectx.ec_stack.ga_len;
10848a7d6542SBram Moolenaar 
10858a7d6542SBram Moolenaar     // Frame pointer points to just after arguments.
1086bf67ea1aSBram Moolenaar     ectx.ec_frame_idx = ectx.ec_stack.ga_len;
1087bf67ea1aSBram Moolenaar     initial_frame_idx = ectx.ec_frame_idx;
10888a7d6542SBram Moolenaar 
10896f5b6dfbSBram Moolenaar     if (partial != NULL)
10906f5b6dfbSBram Moolenaar     {
109108f7a41bSBram Moolenaar 	if (partial->pt_ectx_stack == NULL && current_ectx != NULL)
109208f7a41bSBram Moolenaar 	{
109308f7a41bSBram Moolenaar 	    // TODO: is this always the right way?
109408f7a41bSBram Moolenaar 	    ectx.ec_outer_stack = &current_ectx->ec_stack;
109508f7a41bSBram Moolenaar 	    ectx.ec_outer_frame = current_ectx->ec_frame_idx;
109608f7a41bSBram Moolenaar 	}
109708f7a41bSBram Moolenaar 	else
109808f7a41bSBram Moolenaar 	{
10996f5b6dfbSBram Moolenaar 	    ectx.ec_outer_stack = partial->pt_ectx_stack;
11006f5b6dfbSBram Moolenaar 	    ectx.ec_outer_frame = partial->pt_ectx_frame;
11016f5b6dfbSBram Moolenaar 	}
110208f7a41bSBram Moolenaar     }
1103f112f30aSBram Moolenaar     else if (ufunc->uf_partial != NULL)
1104f112f30aSBram Moolenaar     {
1105f112f30aSBram Moolenaar 	ectx.ec_outer_stack = ufunc->uf_partial->pt_ectx_stack;
1106f112f30aSBram Moolenaar 	ectx.ec_outer_frame = ufunc->uf_partial->pt_ectx_frame;
1107f112f30aSBram Moolenaar     }
11086f5b6dfbSBram Moolenaar 
11098a7d6542SBram Moolenaar     // dummy frame entries
11108a7d6542SBram Moolenaar     for (idx = 0; idx < STACK_FRAME_SIZE; ++idx)
11118a7d6542SBram Moolenaar     {
11128a7d6542SBram Moolenaar 	STACK_TV(ectx.ec_stack.ga_len)->v_type = VAR_UNKNOWN;
11138a7d6542SBram Moolenaar 	++ectx.ec_stack.ga_len;
11148a7d6542SBram Moolenaar     }
11158a7d6542SBram Moolenaar 
1116bd5da371SBram Moolenaar     {
1117148ce7aeSBram Moolenaar 	// Reserve space for local variables and any closure reference count.
1118bd5da371SBram Moolenaar 	dfunc_T	*dfunc = ((dfunc_T *)def_functions.ga_data)
1119bd5da371SBram Moolenaar 							 + ufunc->uf_dfunc_idx;
1120bd5da371SBram Moolenaar 
1121148ce7aeSBram Moolenaar 	for (idx = 0; idx < dfunc->df_varcount; ++idx)
11228a7d6542SBram Moolenaar 	    STACK_TV_VAR(idx)->v_type = VAR_UNKNOWN;
1123148ce7aeSBram Moolenaar 	ectx.ec_stack.ga_len += dfunc->df_varcount;
1124148ce7aeSBram Moolenaar 	if (dfunc->df_has_closure)
1125148ce7aeSBram Moolenaar 	{
1126148ce7aeSBram Moolenaar 	    STACK_TV_VAR(idx)->v_type = VAR_NUMBER;
1127148ce7aeSBram Moolenaar 	    STACK_TV_VAR(idx)->vval.v_number = 0;
1128148ce7aeSBram Moolenaar 	    ++ectx.ec_stack.ga_len;
1129148ce7aeSBram Moolenaar 	}
11308a7d6542SBram Moolenaar 
11318a7d6542SBram Moolenaar 	ectx.ec_instr = dfunc->df_instr;
1132bd5da371SBram Moolenaar     }
1133170fcfcfSBram Moolenaar 
1134ee8580e5SBram Moolenaar     // Following errors are in the function, not the caller.
1135a26b9700SBram Moolenaar     // Commands behave like vim9script.
1136ee8580e5SBram Moolenaar     estack_push_ufunc(ufunc, 1);
1137ee8580e5SBram Moolenaar     current_sctx = ufunc->uf_script_ctx;
1138a26b9700SBram Moolenaar     current_sctx.sc_version = SCRIPT_VERSION_VIM9;
1139a26b9700SBram Moolenaar 
1140352134bbSBram Moolenaar     // Use a specific location for storing error messages to be converted to an
1141352134bbSBram Moolenaar     // exception.
1142352134bbSBram Moolenaar     saved_msg_list = msg_list;
1143352134bbSBram Moolenaar     msg_list = &private_msg_list;
1144352134bbSBram Moolenaar 
114577e5dcc3SBram Moolenaar     // Do turn errors into exceptions.
114677e5dcc3SBram Moolenaar     suppress_errthrow = FALSE;
114777e5dcc3SBram Moolenaar 
114856602ba1SBram Moolenaar     // When ":silent!" was used before calling then we still abort the
114956602ba1SBram Moolenaar     // function.  If ":silent!" is used in the function then we don't.
115056602ba1SBram Moolenaar     emsg_silent_def = emsg_silent;
115156602ba1SBram Moolenaar     did_emsg_def = 0;
115256602ba1SBram Moolenaar 
1153170fcfcfSBram Moolenaar     // Decide where to start execution, handles optional arguments.
1154170fcfcfSBram Moolenaar     init_instr_idx(ufunc, argc, &ectx);
1155170fcfcfSBram Moolenaar 
11568a7d6542SBram Moolenaar     for (;;)
11578a7d6542SBram Moolenaar     {
11588a7d6542SBram Moolenaar 	isn_T	    *iptr;
115920431c9dSBram Moolenaar 
1160270d0388SBram Moolenaar 	if (++breakcheck_count >= 100)
1161270d0388SBram Moolenaar 	{
1162270d0388SBram Moolenaar 	    line_breakcheck();
1163270d0388SBram Moolenaar 	    breakcheck_count = 0;
1164270d0388SBram Moolenaar 	}
116520431c9dSBram Moolenaar 	if (got_int)
116620431c9dSBram Moolenaar 	{
116720431c9dSBram Moolenaar 	    // Turn CTRL-C into an exception.
116820431c9dSBram Moolenaar 	    got_int = FALSE;
116997acfc78SBram Moolenaar 	    if (throw_exception("Vim:Interrupt", ET_INTERRUPT, NULL) == FAIL)
117020431c9dSBram Moolenaar 		goto failed;
117120431c9dSBram Moolenaar 	    did_throw = TRUE;
117220431c9dSBram Moolenaar 	}
11738a7d6542SBram Moolenaar 
1174a26b9700SBram Moolenaar 	if (did_emsg && msg_list != NULL && *msg_list != NULL)
1175a26b9700SBram Moolenaar 	{
1176a26b9700SBram Moolenaar 	    // Turn an error message into an exception.
1177a26b9700SBram Moolenaar 	    did_emsg = FALSE;
1178a26b9700SBram Moolenaar 	    if (throw_exception(*msg_list, ET_ERROR, NULL) == FAIL)
1179a26b9700SBram Moolenaar 		goto failed;
1180a26b9700SBram Moolenaar 	    did_throw = TRUE;
1181a26b9700SBram Moolenaar 	    *msg_list = NULL;
1182a26b9700SBram Moolenaar 	}
1183a26b9700SBram Moolenaar 
11848a7d6542SBram Moolenaar 	if (did_throw && !ectx.ec_in_catch)
11858a7d6542SBram Moolenaar 	{
11868a7d6542SBram Moolenaar 	    garray_T	*trystack = &ectx.ec_trystack;
118720431c9dSBram Moolenaar 	    trycmd_T    *trycmd = NULL;
11888a7d6542SBram Moolenaar 
11898a7d6542SBram Moolenaar 	    // An exception jumps to the first catch, finally, or returns from
11908a7d6542SBram Moolenaar 	    // the current function.
11918a7d6542SBram Moolenaar 	    if (trystack->ga_len > 0)
11928a7d6542SBram Moolenaar 		trycmd = ((trycmd_T *)trystack->ga_data) + trystack->ga_len - 1;
1193bf67ea1aSBram Moolenaar 	    if (trycmd != NULL && trycmd->tcd_frame_idx == ectx.ec_frame_idx)
11948a7d6542SBram Moolenaar 	    {
11958a7d6542SBram Moolenaar 		// jump to ":catch" or ":finally"
11968a7d6542SBram Moolenaar 		ectx.ec_in_catch = TRUE;
11978a7d6542SBram Moolenaar 		ectx.ec_iidx = trycmd->tcd_catch_idx;
11988a7d6542SBram Moolenaar 	    }
11998a7d6542SBram Moolenaar 	    else
12008a7d6542SBram Moolenaar 	    {
1201cdd70f09SBram Moolenaar 		// Not inside try or need to return from current functions.
1202cdd70f09SBram Moolenaar 		// Push a dummy return value.
1203270d0388SBram Moolenaar 		if (GA_GROW(&ectx.ec_stack, 1) == FAIL)
12048a7d6542SBram Moolenaar 		    goto failed;
12058a7d6542SBram Moolenaar 		tv = STACK_TV_BOT(0);
12068a7d6542SBram Moolenaar 		tv->v_type = VAR_NUMBER;
12078a7d6542SBram Moolenaar 		tv->vval.v_number = 0;
12088a7d6542SBram Moolenaar 		++ectx.ec_stack.ga_len;
1209cdd70f09SBram Moolenaar 		if (ectx.ec_frame_idx == initial_frame_idx)
1210cdd70f09SBram Moolenaar 		{
1211cdd70f09SBram Moolenaar 		    // At the toplevel we are done.
1212257cc5eeSBram Moolenaar 		    need_rethrow = TRUE;
1213bf67ea1aSBram Moolenaar 		    if (handle_closure_in_use(&ectx, FALSE) == FAIL)
1214bf67ea1aSBram Moolenaar 			goto failed;
12158a7d6542SBram Moolenaar 		    goto done;
12168a7d6542SBram Moolenaar 		}
12178a7d6542SBram Moolenaar 
1218bf67ea1aSBram Moolenaar 		if (func_return(&ectx) == FAIL)
1219bf67ea1aSBram Moolenaar 		    goto failed;
12208a7d6542SBram Moolenaar 	    }
12218a7d6542SBram Moolenaar 	    continue;
12228a7d6542SBram Moolenaar 	}
12238a7d6542SBram Moolenaar 
12248a7d6542SBram Moolenaar 	iptr = &ectx.ec_instr[ectx.ec_iidx++];
12258a7d6542SBram Moolenaar 	switch (iptr->isn_type)
12268a7d6542SBram Moolenaar 	{
12278a7d6542SBram Moolenaar 	    // execute Ex command line
12288a7d6542SBram Moolenaar 	    case ISN_EXEC:
1229631e8f93SBram Moolenaar 		{
12306378c4feSBram Moolenaar 		    SOURCING_LNUM = iptr->isn_lnum;
12318a7d6542SBram Moolenaar 		    do_cmdline_cmd(iptr->isn_arg.string);
1232eeece9e4SBram Moolenaar 		    if (did_emsg)
1233eeece9e4SBram Moolenaar 			goto on_error;
1234631e8f93SBram Moolenaar 		}
12358a7d6542SBram Moolenaar 		break;
12368a7d6542SBram Moolenaar 
1237cfe435d7SBram Moolenaar 	    // execute Ex command from pieces on the stack
1238cfe435d7SBram Moolenaar 	    case ISN_EXECCONCAT:
1239cfe435d7SBram Moolenaar 		{
1240cfe435d7SBram Moolenaar 		    int	    count = iptr->isn_arg.number;
12417f6f56f4SBram Moolenaar 		    size_t  len = 0;
1242cfe435d7SBram Moolenaar 		    int	    pass;
1243cfe435d7SBram Moolenaar 		    int	    i;
1244cfe435d7SBram Moolenaar 		    char_u  *cmd = NULL;
1245cfe435d7SBram Moolenaar 		    char_u  *str;
1246cfe435d7SBram Moolenaar 
1247cfe435d7SBram Moolenaar 		    for (pass = 1; pass <= 2; ++pass)
1248cfe435d7SBram Moolenaar 		    {
1249cfe435d7SBram Moolenaar 			for (i = 0; i < count; ++i)
1250cfe435d7SBram Moolenaar 			{
1251cfe435d7SBram Moolenaar 			    tv = STACK_TV_BOT(i - count);
1252cfe435d7SBram Moolenaar 			    str = tv->vval.v_string;
1253cfe435d7SBram Moolenaar 			    if (str != NULL && *str != NUL)
1254cfe435d7SBram Moolenaar 			    {
1255cfe435d7SBram Moolenaar 				if (pass == 2)
1256cfe435d7SBram Moolenaar 				    STRCPY(cmd + len, str);
1257cfe435d7SBram Moolenaar 				len += STRLEN(str);
1258cfe435d7SBram Moolenaar 			    }
1259cfe435d7SBram Moolenaar 			    if (pass == 2)
1260cfe435d7SBram Moolenaar 				clear_tv(tv);
1261cfe435d7SBram Moolenaar 			}
1262cfe435d7SBram Moolenaar 			if (pass == 1)
1263cfe435d7SBram Moolenaar 			{
1264cfe435d7SBram Moolenaar 			    cmd = alloc(len + 1);
1265cfe435d7SBram Moolenaar 			    if (cmd == NULL)
1266cfe435d7SBram Moolenaar 				goto failed;
1267cfe435d7SBram Moolenaar 			    len = 0;
1268cfe435d7SBram Moolenaar 			}
1269cfe435d7SBram Moolenaar 		    }
1270cfe435d7SBram Moolenaar 
12716378c4feSBram Moolenaar 		    SOURCING_LNUM = iptr->isn_lnum;
1272cfe435d7SBram Moolenaar 		    do_cmdline_cmd(cmd);
1273cfe435d7SBram Moolenaar 		    vim_free(cmd);
1274cfe435d7SBram Moolenaar 		}
1275cfe435d7SBram Moolenaar 		break;
1276cfe435d7SBram Moolenaar 
12778a7d6542SBram Moolenaar 	    // execute :echo {string} ...
12788a7d6542SBram Moolenaar 	    case ISN_ECHO:
12798a7d6542SBram Moolenaar 		{
12808a7d6542SBram Moolenaar 		    int count = iptr->isn_arg.echo.echo_count;
12818a7d6542SBram Moolenaar 		    int	atstart = TRUE;
12828a7d6542SBram Moolenaar 		    int needclr = TRUE;
12838a7d6542SBram Moolenaar 
12848a7d6542SBram Moolenaar 		    for (idx = 0; idx < count; ++idx)
12858a7d6542SBram Moolenaar 		    {
12868a7d6542SBram Moolenaar 			tv = STACK_TV_BOT(idx - count);
12878a7d6542SBram Moolenaar 			echo_one(tv, iptr->isn_arg.echo.echo_with_white,
12888a7d6542SBram Moolenaar 							   &atstart, &needclr);
12898a7d6542SBram Moolenaar 			clear_tv(tv);
12908a7d6542SBram Moolenaar 		    }
1291e0807ea4SBram Moolenaar 		    if (needclr)
1292e0807ea4SBram Moolenaar 			msg_clr_eos();
12938a7d6542SBram Moolenaar 		    ectx.ec_stack.ga_len -= count;
12948a7d6542SBram Moolenaar 		}
12958a7d6542SBram Moolenaar 		break;
12968a7d6542SBram Moolenaar 
1297f93c7feaSBram Moolenaar 	    // :execute {string} ...
1298f93c7feaSBram Moolenaar 	    // :echomsg {string} ...
1299f93c7feaSBram Moolenaar 	    // :echoerr {string} ...
1300ad39c094SBram Moolenaar 	    case ISN_EXECUTE:
1301f93c7feaSBram Moolenaar 	    case ISN_ECHOMSG:
1302f93c7feaSBram Moolenaar 	    case ISN_ECHOERR:
1303ad39c094SBram Moolenaar 		{
1304ad39c094SBram Moolenaar 		    int		count = iptr->isn_arg.number;
1305ad39c094SBram Moolenaar 		    garray_T	ga;
1306ad39c094SBram Moolenaar 		    char_u	buf[NUMBUFLEN];
1307ad39c094SBram Moolenaar 		    char_u	*p;
1308ad39c094SBram Moolenaar 		    int		len;
1309ad39c094SBram Moolenaar 		    int		failed = FALSE;
1310ad39c094SBram Moolenaar 
1311ad39c094SBram Moolenaar 		    ga_init2(&ga, 1, 80);
1312ad39c094SBram Moolenaar 		    for (idx = 0; idx < count; ++idx)
1313ad39c094SBram Moolenaar 		    {
1314ad39c094SBram Moolenaar 			tv = STACK_TV_BOT(idx - count);
1315e5abf7afSBram Moolenaar 			if (iptr->isn_type == ISN_EXECUTE)
1316e5abf7afSBram Moolenaar 			{
1317e5abf7afSBram Moolenaar 			    if (tv->v_type == VAR_CHANNEL
1318e5abf7afSBram Moolenaar 						      || tv->v_type == VAR_JOB)
1319ad39c094SBram Moolenaar 			    {
13207517ffdbSBram Moolenaar 				SOURCING_LNUM = iptr->isn_lnum;
1321ad39c094SBram Moolenaar 				emsg(_(e_inval_string));
1322ad39c094SBram Moolenaar 				break;
1323ad39c094SBram Moolenaar 			    }
1324ad39c094SBram Moolenaar 			    else
1325ad39c094SBram Moolenaar 				p = tv_get_string_buf(tv, buf);
1326e5abf7afSBram Moolenaar 			}
1327e5abf7afSBram Moolenaar 			else
1328e5abf7afSBram Moolenaar 			    p = tv_stringify(tv, buf);
1329ad39c094SBram Moolenaar 
1330ad39c094SBram Moolenaar 			len = (int)STRLEN(p);
1331ad39c094SBram Moolenaar 			if (ga_grow(&ga, len + 2) == FAIL)
1332ad39c094SBram Moolenaar 			    failed = TRUE;
1333ad39c094SBram Moolenaar 			else
1334ad39c094SBram Moolenaar 			{
1335ad39c094SBram Moolenaar 			    if (ga.ga_len > 0)
1336ad39c094SBram Moolenaar 				((char_u *)(ga.ga_data))[ga.ga_len++] = ' ';
1337ad39c094SBram Moolenaar 			    STRCPY((char_u *)(ga.ga_data) + ga.ga_len, p);
1338ad39c094SBram Moolenaar 			    ga.ga_len += len;
1339ad39c094SBram Moolenaar 			}
1340ad39c094SBram Moolenaar 			clear_tv(tv);
1341ad39c094SBram Moolenaar 		    }
1342ad39c094SBram Moolenaar 		    ectx.ec_stack.ga_len -= count;
1343e5abf7afSBram Moolenaar 		    if (failed)
1344c71ee829SBram Moolenaar 		    {
1345c71ee829SBram Moolenaar 			ga_clear(&ga);
1346e5abf7afSBram Moolenaar 			goto on_error;
1347c71ee829SBram Moolenaar 		    }
1348ad39c094SBram Moolenaar 
1349e5abf7afSBram Moolenaar 		    if (ga.ga_data != NULL)
1350f93c7feaSBram Moolenaar 		    {
1351f93c7feaSBram Moolenaar 			if (iptr->isn_type == ISN_EXECUTE)
1352430deb19SBram Moolenaar 			{
1353430deb19SBram Moolenaar 			    SOURCING_LNUM = iptr->isn_lnum;
1354ad39c094SBram Moolenaar 			    do_cmdline_cmd((char_u *)ga.ga_data);
1355eeece9e4SBram Moolenaar 			    if (did_emsg)
1356c71ee829SBram Moolenaar 			    {
1357c71ee829SBram Moolenaar 				ga_clear(&ga);
1358eeece9e4SBram Moolenaar 				goto on_error;
1359430deb19SBram Moolenaar 			    }
1360c71ee829SBram Moolenaar 			}
1361f93c7feaSBram Moolenaar 			else
1362f93c7feaSBram Moolenaar 			{
1363f93c7feaSBram Moolenaar 			    msg_sb_eol();
1364f93c7feaSBram Moolenaar 			    if (iptr->isn_type == ISN_ECHOMSG)
1365f93c7feaSBram Moolenaar 			    {
1366f93c7feaSBram Moolenaar 				msg_attr(ga.ga_data, echo_attr);
1367f93c7feaSBram Moolenaar 				out_flush();
1368f93c7feaSBram Moolenaar 			    }
1369f93c7feaSBram Moolenaar 			    else
1370f93c7feaSBram Moolenaar 			    {
1371f93c7feaSBram Moolenaar 				SOURCING_LNUM = iptr->isn_lnum;
1372f93c7feaSBram Moolenaar 				emsg(ga.ga_data);
1373f93c7feaSBram Moolenaar 			    }
1374f93c7feaSBram Moolenaar 			}
1375f93c7feaSBram Moolenaar 		    }
1376ad39c094SBram Moolenaar 		    ga_clear(&ga);
1377ad39c094SBram Moolenaar 		}
1378ad39c094SBram Moolenaar 		break;
1379ad39c094SBram Moolenaar 
13808a7d6542SBram Moolenaar 	    // load local variable or argument
13818a7d6542SBram Moolenaar 	    case ISN_LOAD:
1382270d0388SBram Moolenaar 		if (GA_GROW(&ectx.ec_stack, 1) == FAIL)
13838a7d6542SBram Moolenaar 		    goto failed;
13848a7d6542SBram Moolenaar 		copy_tv(STACK_TV_VAR(iptr->isn_arg.number), STACK_TV_BOT(0));
13858a7d6542SBram Moolenaar 		++ectx.ec_stack.ga_len;
13868a7d6542SBram Moolenaar 		break;
13878a7d6542SBram Moolenaar 
1388c8cd2b34SBram Moolenaar 	    // load variable or argument from outer scope
1389c8cd2b34SBram Moolenaar 	    case ISN_LOADOUTER:
1390270d0388SBram Moolenaar 		if (GA_GROW(&ectx.ec_stack, 1) == FAIL)
1391c8cd2b34SBram Moolenaar 		    goto failed;
1392c8cd2b34SBram Moolenaar 		copy_tv(STACK_OUT_TV_VAR(iptr->isn_arg.number),
1393c8cd2b34SBram Moolenaar 							      STACK_TV_BOT(0));
1394c8cd2b34SBram Moolenaar 		++ectx.ec_stack.ga_len;
1395c8cd2b34SBram Moolenaar 		break;
1396c8cd2b34SBram Moolenaar 
13978a7d6542SBram Moolenaar 	    // load v: variable
13988a7d6542SBram Moolenaar 	    case ISN_LOADV:
1399270d0388SBram Moolenaar 		if (GA_GROW(&ectx.ec_stack, 1) == FAIL)
14008a7d6542SBram Moolenaar 		    goto failed;
14018a7d6542SBram Moolenaar 		copy_tv(get_vim_var_tv(iptr->isn_arg.number), STACK_TV_BOT(0));
14028a7d6542SBram Moolenaar 		++ectx.ec_stack.ga_len;
14038a7d6542SBram Moolenaar 		break;
14048a7d6542SBram Moolenaar 
1405b283a8a6SBram Moolenaar 	    // load s: variable in Vim9 script
14068a7d6542SBram Moolenaar 	    case ISN_LOADSCRIPT:
14078a7d6542SBram Moolenaar 		{
14084aab88d9SBram Moolenaar 		    scriptref_T	*sref = iptr->isn_arg.script.scriptref;
14094aab88d9SBram Moolenaar 		    dfunc_T	*dfunc = ((dfunc_T *)def_functions.ga_data)
14104aab88d9SBram Moolenaar 							  + ectx.ec_dfunc_idx;
14114aab88d9SBram Moolenaar 		    scriptitem_T *si = SCRIPT_ITEM(sref->sref_sid);
14128a7d6542SBram Moolenaar 		    svar_T	 *sv;
14138a7d6542SBram Moolenaar 
14144aab88d9SBram Moolenaar 		    if (sref->sref_seq != si->sn_script_seq)
14154aab88d9SBram Moolenaar 		    {
14164aab88d9SBram Moolenaar 			// The script was reloaded after the function was
14174aab88d9SBram Moolenaar 			// compiled, the script_idx may not be valid.
14184aab88d9SBram Moolenaar 			semsg(_(e_script_variable_invalid_after_reload_in_function_str),
14194aab88d9SBram Moolenaar 						  dfunc->df_ufunc->uf_name_exp);
14204aab88d9SBram Moolenaar 			goto failed;
14214aab88d9SBram Moolenaar 		    }
14224aab88d9SBram Moolenaar 		    sv = ((svar_T *)si->sn_var_vals.ga_data) + sref->sref_idx;
14233beaf9cdSBram Moolenaar 		    allocate_if_null(sv->sv_tv);
1424270d0388SBram Moolenaar 		    if (GA_GROW(&ectx.ec_stack, 1) == FAIL)
14258a7d6542SBram Moolenaar 			goto failed;
14268a7d6542SBram Moolenaar 		    copy_tv(sv->sv_tv, STACK_TV_BOT(0));
14278a7d6542SBram Moolenaar 		    ++ectx.ec_stack.ga_len;
14288a7d6542SBram Moolenaar 		}
14298a7d6542SBram Moolenaar 		break;
14308a7d6542SBram Moolenaar 
14318a7d6542SBram Moolenaar 	    // load s: variable in old script
14328a7d6542SBram Moolenaar 	    case ISN_LOADS:
14338a7d6542SBram Moolenaar 		{
1434b283a8a6SBram Moolenaar 		    hashtab_T	*ht = &SCRIPT_VARS(
1435b283a8a6SBram Moolenaar 					       iptr->isn_arg.loadstore.ls_sid);
1436b283a8a6SBram Moolenaar 		    char_u	*name = iptr->isn_arg.loadstore.ls_name;
14378a7d6542SBram Moolenaar 		    dictitem_T	*di = find_var_in_ht(ht, 0, name, TRUE);
14380bbf722aSBram Moolenaar 
14398a7d6542SBram Moolenaar 		    if (di == NULL)
14408a7d6542SBram Moolenaar 		    {
14417517ffdbSBram Moolenaar 			SOURCING_LNUM = iptr->isn_lnum;
1442451c2e35SBram Moolenaar 			semsg(_(e_undefined_variable_str), name);
1443f0b9f43cSBram Moolenaar 			goto on_error;
14448a7d6542SBram Moolenaar 		    }
14458a7d6542SBram Moolenaar 		    else
14468a7d6542SBram Moolenaar 		    {
1447270d0388SBram Moolenaar 			if (GA_GROW(&ectx.ec_stack, 1) == FAIL)
14488a7d6542SBram Moolenaar 			    goto failed;
14498a7d6542SBram Moolenaar 			copy_tv(&di->di_tv, STACK_TV_BOT(0));
14508a7d6542SBram Moolenaar 			++ectx.ec_stack.ga_len;
14518a7d6542SBram Moolenaar 		    }
14528a7d6542SBram Moolenaar 		}
14538a7d6542SBram Moolenaar 		break;
14548a7d6542SBram Moolenaar 
1455d3aac291SBram Moolenaar 	    // load g:/b:/w:/t: variable
14568a7d6542SBram Moolenaar 	    case ISN_LOADG:
1457d3aac291SBram Moolenaar 	    case ISN_LOADB:
1458d3aac291SBram Moolenaar 	    case ISN_LOADW:
1459d3aac291SBram Moolenaar 	    case ISN_LOADT:
14608a7d6542SBram Moolenaar 		{
1461d3aac291SBram Moolenaar 		    dictitem_T *di = NULL;
1462d3aac291SBram Moolenaar 		    hashtab_T *ht = NULL;
1463d3aac291SBram Moolenaar 		    char namespace;
14642f8ce0aeSBram Moolenaar 
1465d3aac291SBram Moolenaar 		    switch (iptr->isn_type)
1466d3aac291SBram Moolenaar 		    {
1467d3aac291SBram Moolenaar 			case ISN_LOADG:
1468d3aac291SBram Moolenaar 			    ht = get_globvar_ht();
1469d3aac291SBram Moolenaar 			    namespace = 'g';
1470d3aac291SBram Moolenaar 			    break;
1471d3aac291SBram Moolenaar 			case ISN_LOADB:
1472d3aac291SBram Moolenaar 			    ht = &curbuf->b_vars->dv_hashtab;
1473d3aac291SBram Moolenaar 			    namespace = 'b';
1474d3aac291SBram Moolenaar 			    break;
1475d3aac291SBram Moolenaar 			case ISN_LOADW:
1476d3aac291SBram Moolenaar 			    ht = &curwin->w_vars->dv_hashtab;
1477d3aac291SBram Moolenaar 			    namespace = 'w';
1478d3aac291SBram Moolenaar 			    break;
1479d3aac291SBram Moolenaar 			case ISN_LOADT:
1480d3aac291SBram Moolenaar 			    ht = &curtab->tp_vars->dv_hashtab;
1481d3aac291SBram Moolenaar 			    namespace = 't';
1482d3aac291SBram Moolenaar 			    break;
1483d3aac291SBram Moolenaar 			default:  // Cannot reach here
1484d3aac291SBram Moolenaar 			    goto failed;
1485d3aac291SBram Moolenaar 		    }
1486d3aac291SBram Moolenaar 		    di = find_var_in_ht(ht, 0, iptr->isn_arg.string, TRUE);
14870bbf722aSBram Moolenaar 
14888a7d6542SBram Moolenaar 		    if (di == NULL)
14898a7d6542SBram Moolenaar 		    {
14907517ffdbSBram Moolenaar 			SOURCING_LNUM = iptr->isn_lnum;
1491451c2e35SBram Moolenaar 			semsg(_(e_undefined_variable_char_str),
1492d3aac291SBram Moolenaar 					     namespace, iptr->isn_arg.string);
1493f0b9f43cSBram Moolenaar 			goto on_error;
14948a7d6542SBram Moolenaar 		    }
14958a7d6542SBram Moolenaar 		    else
14968a7d6542SBram Moolenaar 		    {
1497270d0388SBram Moolenaar 			if (GA_GROW(&ectx.ec_stack, 1) == FAIL)
14988a7d6542SBram Moolenaar 			    goto failed;
14998a7d6542SBram Moolenaar 			copy_tv(&di->di_tv, STACK_TV_BOT(0));
15008a7d6542SBram Moolenaar 			++ectx.ec_stack.ga_len;
15018a7d6542SBram Moolenaar 		    }
15028a7d6542SBram Moolenaar 		}
15038a7d6542SBram Moolenaar 		break;
15048a7d6542SBram Moolenaar 
150503290b84SBram Moolenaar 	    // load autoload variable
150603290b84SBram Moolenaar 	    case ISN_LOADAUTO:
150703290b84SBram Moolenaar 		{
150803290b84SBram Moolenaar 		    char_u *name = iptr->isn_arg.string;
150903290b84SBram Moolenaar 
151003290b84SBram Moolenaar 		    if (GA_GROW(&ectx.ec_stack, 1) == FAIL)
151103290b84SBram Moolenaar 			goto failed;
151203290b84SBram Moolenaar 		    SOURCING_LNUM = iptr->isn_lnum;
151303290b84SBram Moolenaar 		    if (eval_variable(name, STRLEN(name),
151403290b84SBram Moolenaar 				  STACK_TV_BOT(0), NULL, TRUE, FALSE) == FAIL)
151503290b84SBram Moolenaar 			goto on_error;
151603290b84SBram Moolenaar 		    ++ectx.ec_stack.ga_len;
151703290b84SBram Moolenaar 		}
151803290b84SBram Moolenaar 		break;
151903290b84SBram Moolenaar 
15202f8ce0aeSBram Moolenaar 	    // load g:/b:/w:/t: namespace
15212f8ce0aeSBram Moolenaar 	    case ISN_LOADGDICT:
15222f8ce0aeSBram Moolenaar 	    case ISN_LOADBDICT:
15232f8ce0aeSBram Moolenaar 	    case ISN_LOADWDICT:
15242f8ce0aeSBram Moolenaar 	    case ISN_LOADTDICT:
15252f8ce0aeSBram Moolenaar 		{
15262f8ce0aeSBram Moolenaar 		    dict_T *d = NULL;
15272f8ce0aeSBram Moolenaar 
15282f8ce0aeSBram Moolenaar 		    switch (iptr->isn_type)
15292f8ce0aeSBram Moolenaar 		    {
1530682d0a15SBram Moolenaar 			case ISN_LOADGDICT: d = get_globvar_dict(); break;
1531682d0a15SBram Moolenaar 			case ISN_LOADBDICT: d = curbuf->b_vars; break;
1532682d0a15SBram Moolenaar 			case ISN_LOADWDICT: d = curwin->w_vars; break;
1533682d0a15SBram Moolenaar 			case ISN_LOADTDICT: d = curtab->tp_vars; break;
15342f8ce0aeSBram Moolenaar 			default:  // Cannot reach here
15352f8ce0aeSBram Moolenaar 			    goto failed;
15362f8ce0aeSBram Moolenaar 		    }
15372f8ce0aeSBram Moolenaar 		    if (GA_GROW(&ectx.ec_stack, 1) == FAIL)
15382f8ce0aeSBram Moolenaar 			goto failed;
15392f8ce0aeSBram Moolenaar 		    tv = STACK_TV_BOT(0);
15402f8ce0aeSBram Moolenaar 		    tv->v_type = VAR_DICT;
15412f8ce0aeSBram Moolenaar 		    tv->v_lock = 0;
15422f8ce0aeSBram Moolenaar 		    tv->vval.v_dict = d;
15432f8ce0aeSBram Moolenaar 		    ++ectx.ec_stack.ga_len;
15442f8ce0aeSBram Moolenaar 		}
15452f8ce0aeSBram Moolenaar 		break;
15462f8ce0aeSBram Moolenaar 
15478a7d6542SBram Moolenaar 	    // load &option
15488a7d6542SBram Moolenaar 	    case ISN_LOADOPT:
15498a7d6542SBram Moolenaar 		{
15508a7d6542SBram Moolenaar 		    typval_T	optval;
15518a7d6542SBram Moolenaar 		    char_u	*name = iptr->isn_arg.string;
15528a7d6542SBram Moolenaar 
1553a8c17704SBram Moolenaar 		    // This is not expected to fail, name is checked during
1554a8c17704SBram Moolenaar 		    // compilation: don't set SOURCING_LNUM.
1555270d0388SBram Moolenaar 		    if (GA_GROW(&ectx.ec_stack, 1) == FAIL)
15568a7d6542SBram Moolenaar 			goto failed;
15579a78e6dfSBram Moolenaar 		    if (eval_option(&name, &optval, TRUE) == FAIL)
155858ceca5cSBram Moolenaar 			goto failed;
15598a7d6542SBram Moolenaar 		    *STACK_TV_BOT(0) = optval;
15608a7d6542SBram Moolenaar 		    ++ectx.ec_stack.ga_len;
15618a7d6542SBram Moolenaar 		}
15628a7d6542SBram Moolenaar 		break;
15638a7d6542SBram Moolenaar 
15648a7d6542SBram Moolenaar 	    // load $ENV
15658a7d6542SBram Moolenaar 	    case ISN_LOADENV:
15668a7d6542SBram Moolenaar 		{
15678a7d6542SBram Moolenaar 		    typval_T	optval;
15688a7d6542SBram Moolenaar 		    char_u	*name = iptr->isn_arg.string;
15698a7d6542SBram Moolenaar 
1570270d0388SBram Moolenaar 		    if (GA_GROW(&ectx.ec_stack, 1) == FAIL)
15718a7d6542SBram Moolenaar 			goto failed;
15720bbf722aSBram Moolenaar 		    // name is always valid, checked when compiling
15739a78e6dfSBram Moolenaar 		    (void)eval_env_var(&name, &optval, TRUE);
15748a7d6542SBram Moolenaar 		    *STACK_TV_BOT(0) = optval;
15758a7d6542SBram Moolenaar 		    ++ectx.ec_stack.ga_len;
15768a7d6542SBram Moolenaar 		}
15778a7d6542SBram Moolenaar 		break;
15788a7d6542SBram Moolenaar 
15798a7d6542SBram Moolenaar 	    // load @register
15808a7d6542SBram Moolenaar 	    case ISN_LOADREG:
1581270d0388SBram Moolenaar 		if (GA_GROW(&ectx.ec_stack, 1) == FAIL)
15828a7d6542SBram Moolenaar 		    goto failed;
15838a7d6542SBram Moolenaar 		tv = STACK_TV_BOT(0);
15848a7d6542SBram Moolenaar 		tv->v_type = VAR_STRING;
15852f8ce0aeSBram Moolenaar 		tv->v_lock = 0;
15861e021e63SBram Moolenaar 		// This may result in NULL, which should be equivalent to an
15871e021e63SBram Moolenaar 		// empty string.
15888a7d6542SBram Moolenaar 		tv->vval.v_string = get_reg_contents(
15898a7d6542SBram Moolenaar 					  iptr->isn_arg.number, GREG_EXPR_SRC);
15908a7d6542SBram Moolenaar 		++ectx.ec_stack.ga_len;
15918a7d6542SBram Moolenaar 		break;
15928a7d6542SBram Moolenaar 
15938a7d6542SBram Moolenaar 	    // store local variable
15948a7d6542SBram Moolenaar 	    case ISN_STORE:
15958a7d6542SBram Moolenaar 		--ectx.ec_stack.ga_len;
15968a7d6542SBram Moolenaar 		tv = STACK_TV_VAR(iptr->isn_arg.number);
15978a7d6542SBram Moolenaar 		clear_tv(tv);
15988a7d6542SBram Moolenaar 		*tv = *STACK_TV_BOT(0);
15998a7d6542SBram Moolenaar 		break;
16008a7d6542SBram Moolenaar 
1601b68b346eSBram Moolenaar 	    // store variable or argument in outer scope
1602b68b346eSBram Moolenaar 	    case ISN_STOREOUTER:
1603b68b346eSBram Moolenaar 		--ectx.ec_stack.ga_len;
1604b68b346eSBram Moolenaar 		tv = STACK_OUT_TV_VAR(iptr->isn_arg.number);
1605b68b346eSBram Moolenaar 		clear_tv(tv);
1606b68b346eSBram Moolenaar 		*tv = *STACK_TV_BOT(0);
1607b68b346eSBram Moolenaar 		break;
1608b68b346eSBram Moolenaar 
1609b283a8a6SBram Moolenaar 	    // store s: variable in old script
1610b283a8a6SBram Moolenaar 	    case ISN_STORES:
1611b283a8a6SBram Moolenaar 		{
1612b283a8a6SBram Moolenaar 		    hashtab_T	*ht = &SCRIPT_VARS(
1613b283a8a6SBram Moolenaar 					       iptr->isn_arg.loadstore.ls_sid);
1614b283a8a6SBram Moolenaar 		    char_u	*name = iptr->isn_arg.loadstore.ls_name;
16150bbf722aSBram Moolenaar 		    dictitem_T	*di = find_var_in_ht(ht, 0, name + 2, TRUE);
1616b283a8a6SBram Moolenaar 
1617b283a8a6SBram Moolenaar 		    --ectx.ec_stack.ga_len;
16180bbf722aSBram Moolenaar 		    if (di == NULL)
16195deeb3f1SBram Moolenaar 			store_var(name, STACK_TV_BOT(0));
16200bbf722aSBram Moolenaar 		    else
16210bbf722aSBram Moolenaar 		    {
1622b283a8a6SBram Moolenaar 			clear_tv(&di->di_tv);
1623b283a8a6SBram Moolenaar 			di->di_tv = *STACK_TV_BOT(0);
1624b283a8a6SBram Moolenaar 		    }
16250bbf722aSBram Moolenaar 		}
1626b283a8a6SBram Moolenaar 		break;
1627b283a8a6SBram Moolenaar 
1628b283a8a6SBram Moolenaar 	    // store script-local variable in Vim9 script
16298a7d6542SBram Moolenaar 	    case ISN_STORESCRIPT:
16308a7d6542SBram Moolenaar 		{
16314aab88d9SBram Moolenaar 		    scriptref_T	*sref = iptr->isn_arg.script.scriptref;
16324aab88d9SBram Moolenaar 		    dfunc_T	*dfunc = ((dfunc_T *)def_functions.ga_data)
16334aab88d9SBram Moolenaar 							  + ectx.ec_dfunc_idx;
16344aab88d9SBram Moolenaar 		    scriptitem_T *si = SCRIPT_ITEM(sref->sref_sid);
16354aab88d9SBram Moolenaar 		    svar_T	 *sv;
16368a7d6542SBram Moolenaar 
16374aab88d9SBram Moolenaar 		    if (sref->sref_seq != si->sn_script_seq)
16384aab88d9SBram Moolenaar 		    {
16394aab88d9SBram Moolenaar 			// The script was reloaded after the function was
16404aab88d9SBram Moolenaar 			// compiled, the script_idx may not be valid.
16414aab88d9SBram Moolenaar 			SOURCING_LNUM = iptr->isn_lnum;
16424aab88d9SBram Moolenaar 			semsg(_(e_script_variable_invalid_after_reload_in_function_str),
16434aab88d9SBram Moolenaar 						  dfunc->df_ufunc->uf_name_exp);
16444aab88d9SBram Moolenaar 			goto failed;
16454aab88d9SBram Moolenaar 		    }
16464aab88d9SBram Moolenaar 		    sv = ((svar_T *)si->sn_var_vals.ga_data) + sref->sref_idx;
16478a7d6542SBram Moolenaar 		    --ectx.ec_stack.ga_len;
16488a7d6542SBram Moolenaar 		    clear_tv(sv->sv_tv);
16498a7d6542SBram Moolenaar 		    *sv->sv_tv = *STACK_TV_BOT(0);
16508a7d6542SBram Moolenaar 		}
16518a7d6542SBram Moolenaar 		break;
16528a7d6542SBram Moolenaar 
16538a7d6542SBram Moolenaar 	    // store option
16548a7d6542SBram Moolenaar 	    case ISN_STOREOPT:
16558a7d6542SBram Moolenaar 		{
16568a7d6542SBram Moolenaar 		    long	n = 0;
16578a7d6542SBram Moolenaar 		    char_u	*s = NULL;
16588a7d6542SBram Moolenaar 		    char	*msg;
16598a7d6542SBram Moolenaar 
16608a7d6542SBram Moolenaar 		    --ectx.ec_stack.ga_len;
16618a7d6542SBram Moolenaar 		    tv = STACK_TV_BOT(0);
16628a7d6542SBram Moolenaar 		    if (tv->v_type == VAR_STRING)
166397a2af39SBram Moolenaar 		    {
16648a7d6542SBram Moolenaar 			s = tv->vval.v_string;
166597a2af39SBram Moolenaar 			if (s == NULL)
166697a2af39SBram Moolenaar 			    s = (char_u *)"";
166797a2af39SBram Moolenaar 		    }
16688a7d6542SBram Moolenaar 		    else
1669a6e67e4fSBram Moolenaar 			// must be VAR_NUMBER, CHECKTYPE makes sure
1670a6e67e4fSBram Moolenaar 			n = tv->vval.v_number;
16718a7d6542SBram Moolenaar 		    msg = set_option_value(iptr->isn_arg.storeopt.so_name,
16728a7d6542SBram Moolenaar 					n, s, iptr->isn_arg.storeopt.so_flags);
1673e75ba268SBram Moolenaar 		    clear_tv(tv);
16748a7d6542SBram Moolenaar 		    if (msg != NULL)
16758a7d6542SBram Moolenaar 		    {
16767517ffdbSBram Moolenaar 			SOURCING_LNUM = iptr->isn_lnum;
16778a7d6542SBram Moolenaar 			emsg(_(msg));
1678e859312eSBram Moolenaar 			goto on_error;
16798a7d6542SBram Moolenaar 		    }
16808a7d6542SBram Moolenaar 		}
16818a7d6542SBram Moolenaar 		break;
16828a7d6542SBram Moolenaar 
1683b283a8a6SBram Moolenaar 	    // store $ENV
1684b283a8a6SBram Moolenaar 	    case ISN_STOREENV:
1685b283a8a6SBram Moolenaar 		--ectx.ec_stack.ga_len;
168620431c9dSBram Moolenaar 		tv = STACK_TV_BOT(0);
168720431c9dSBram Moolenaar 		vim_setenv_ext(iptr->isn_arg.string, tv_get_string(tv));
168820431c9dSBram Moolenaar 		clear_tv(tv);
1689b283a8a6SBram Moolenaar 		break;
1690b283a8a6SBram Moolenaar 
1691b283a8a6SBram Moolenaar 	    // store @r
1692b283a8a6SBram Moolenaar 	    case ISN_STOREREG:
1693b283a8a6SBram Moolenaar 		{
1694b283a8a6SBram Moolenaar 		    int	reg = iptr->isn_arg.number;
1695b283a8a6SBram Moolenaar 
1696b283a8a6SBram Moolenaar 		    --ectx.ec_stack.ga_len;
1697401d9ffbSBram Moolenaar 		    tv = STACK_TV_BOT(0);
1698b283a8a6SBram Moolenaar 		    write_reg_contents(reg == '@' ? '"' : reg,
1699401d9ffbSBram Moolenaar 						 tv_get_string(tv), -1, FALSE);
1700401d9ffbSBram Moolenaar 		    clear_tv(tv);
1701b283a8a6SBram Moolenaar 		}
1702b283a8a6SBram Moolenaar 		break;
1703b283a8a6SBram Moolenaar 
1704b283a8a6SBram Moolenaar 	    // store v: variable
1705b283a8a6SBram Moolenaar 	    case ISN_STOREV:
1706b283a8a6SBram Moolenaar 		--ectx.ec_stack.ga_len;
1707b283a8a6SBram Moolenaar 		if (set_vim_var_tv(iptr->isn_arg.number, STACK_TV_BOT(0))
1708b283a8a6SBram Moolenaar 								       == FAIL)
1709e859312eSBram Moolenaar 		    // should not happen, type is checked when compiling
1710e859312eSBram Moolenaar 		    goto on_error;
1711b283a8a6SBram Moolenaar 		break;
1712b283a8a6SBram Moolenaar 
1713d3aac291SBram Moolenaar 	    // store g:/b:/w:/t: variable
17148a7d6542SBram Moolenaar 	    case ISN_STOREG:
1715d3aac291SBram Moolenaar 	    case ISN_STOREB:
1716d3aac291SBram Moolenaar 	    case ISN_STOREW:
1717d3aac291SBram Moolenaar 	    case ISN_STORET:
17188a7d6542SBram Moolenaar 		{
17198a7d6542SBram Moolenaar 		    dictitem_T	*di;
1720d3aac291SBram Moolenaar 		    hashtab_T	*ht;
17213bdc90b7SBram Moolenaar 		    char_u	*name = iptr->isn_arg.string + 2;
17223bdc90b7SBram Moolenaar 
1723d3aac291SBram Moolenaar 		    switch (iptr->isn_type)
1724d3aac291SBram Moolenaar 		    {
1725d3aac291SBram Moolenaar 			case ISN_STOREG:
1726d3aac291SBram Moolenaar 			    ht = get_globvar_ht();
1727d3aac291SBram Moolenaar 			    break;
1728d3aac291SBram Moolenaar 			case ISN_STOREB:
1729d3aac291SBram Moolenaar 			    ht = &curbuf->b_vars->dv_hashtab;
1730d3aac291SBram Moolenaar 			    break;
1731d3aac291SBram Moolenaar 			case ISN_STOREW:
1732d3aac291SBram Moolenaar 			    ht = &curwin->w_vars->dv_hashtab;
1733d3aac291SBram Moolenaar 			    break;
1734d3aac291SBram Moolenaar 			case ISN_STORET:
1735d3aac291SBram Moolenaar 			    ht = &curtab->tp_vars->dv_hashtab;
1736d3aac291SBram Moolenaar 			    break;
1737d3aac291SBram Moolenaar 			default:  // Cannot reach here
1738d3aac291SBram Moolenaar 			    goto failed;
1739d3aac291SBram Moolenaar 		    }
17408a7d6542SBram Moolenaar 
17418a7d6542SBram Moolenaar 		    --ectx.ec_stack.ga_len;
17423bdc90b7SBram Moolenaar 		    di = find_var_in_ht(ht, 0, name, TRUE);
17438a7d6542SBram Moolenaar 		    if (di == NULL)
17440bbf722aSBram Moolenaar 			store_var(iptr->isn_arg.string, STACK_TV_BOT(0));
17458a7d6542SBram Moolenaar 		    else
17468a7d6542SBram Moolenaar 		    {
17473bdc90b7SBram Moolenaar 			SOURCING_LNUM = iptr->isn_lnum;
17483bdc90b7SBram Moolenaar 			if (var_check_permission(di, name) == FAIL)
17493bdc90b7SBram Moolenaar 			    goto on_error;
17508a7d6542SBram Moolenaar 			clear_tv(&di->di_tv);
17518a7d6542SBram Moolenaar 			di->di_tv = *STACK_TV_BOT(0);
17528a7d6542SBram Moolenaar 		    }
17538a7d6542SBram Moolenaar 		}
17548a7d6542SBram Moolenaar 		break;
17558a7d6542SBram Moolenaar 
175603290b84SBram Moolenaar 	    // store an autoload variable
175703290b84SBram Moolenaar 	    case ISN_STOREAUTO:
175803290b84SBram Moolenaar 		SOURCING_LNUM = iptr->isn_lnum;
175903290b84SBram Moolenaar 		set_var(iptr->isn_arg.string, STACK_TV_BOT(-1), TRUE);
176003290b84SBram Moolenaar 		clear_tv(STACK_TV_BOT(-1));
176103290b84SBram Moolenaar 		--ectx.ec_stack.ga_len;
176203290b84SBram Moolenaar 		break;
176303290b84SBram Moolenaar 
17648a7d6542SBram Moolenaar 	    // store number in local variable
17658a7d6542SBram Moolenaar 	    case ISN_STORENR:
1766a471eeaeSBram Moolenaar 		tv = STACK_TV_VAR(iptr->isn_arg.storenr.stnr_idx);
17678a7d6542SBram Moolenaar 		clear_tv(tv);
17688a7d6542SBram Moolenaar 		tv->v_type = VAR_NUMBER;
1769a471eeaeSBram Moolenaar 		tv->vval.v_number = iptr->isn_arg.storenr.stnr_val;
17708a7d6542SBram Moolenaar 		break;
17718a7d6542SBram Moolenaar 
17724f5e3977SBram Moolenaar 	    // store value in list or dict variable
17734f5e3977SBram Moolenaar 	    case ISN_STOREINDEX:
17741cc2a94fSBram Moolenaar 		{
17754f5e3977SBram Moolenaar 		    vartype_T	dest_type = iptr->isn_arg.vartype;
17761cc2a94fSBram Moolenaar 		    typval_T	*tv_idx = STACK_TV_BOT(-2);
17774f5e3977SBram Moolenaar 		    typval_T	*tv_dest = STACK_TV_BOT(-1);
17784f5e3977SBram Moolenaar 		    int		status = OK;
17791cc2a94fSBram Moolenaar 
17804f5e3977SBram Moolenaar 		    tv = STACK_TV_BOT(-3);
17810b4c66c6SBram Moolenaar 		    SOURCING_LNUM = iptr->isn_lnum;
17824f5e3977SBram Moolenaar 		    if (dest_type == VAR_ANY)
17834f5e3977SBram Moolenaar 		    {
17844f5e3977SBram Moolenaar 			dest_type = tv_dest->v_type;
17854f5e3977SBram Moolenaar 			if (dest_type == VAR_DICT)
17864f5e3977SBram Moolenaar 			    status = do_2string(tv_idx, TRUE);
17874f5e3977SBram Moolenaar 			else if (dest_type == VAR_LIST
17884f5e3977SBram Moolenaar 					       && tv_idx->v_type != VAR_NUMBER)
17894f5e3977SBram Moolenaar 			{
17904f5e3977SBram Moolenaar 			    emsg(_(e_number_exp));
17914f5e3977SBram Moolenaar 			    status = FAIL;
17924f5e3977SBram Moolenaar 			}
17934f5e3977SBram Moolenaar 		    }
17944f5e3977SBram Moolenaar 		    else if (dest_type != tv_dest->v_type)
17954f5e3977SBram Moolenaar 		    {
17964f5e3977SBram Moolenaar 			// just in case, should be OK
17974f5e3977SBram Moolenaar 			semsg(_(e_expected_str_but_got_str),
17984f5e3977SBram Moolenaar 				    vartype_name(dest_type),
17994f5e3977SBram Moolenaar 				    vartype_name(tv_dest->v_type));
18004f5e3977SBram Moolenaar 			status = FAIL;
18014f5e3977SBram Moolenaar 		    }
18024f5e3977SBram Moolenaar 
18034f5e3977SBram Moolenaar 		    if (status == OK && dest_type == VAR_LIST)
18044f5e3977SBram Moolenaar 		    {
18054f5e3977SBram Moolenaar 			varnumber_T	lidx = tv_idx->vval.v_number;
18064f5e3977SBram Moolenaar 			list_T		*list = tv_dest->vval.v_list;
18074f5e3977SBram Moolenaar 
18084f5e3977SBram Moolenaar 			if (list == NULL)
18094f5e3977SBram Moolenaar 			{
18104f5e3977SBram Moolenaar 			    emsg(_(e_list_not_set));
18114f5e3977SBram Moolenaar 			    goto on_error;
18124f5e3977SBram Moolenaar 			}
18131cc2a94fSBram Moolenaar 			if (lidx < 0 && list->lv_len + lidx >= 0)
18141cc2a94fSBram Moolenaar 			    // negative index is relative to the end
18151cc2a94fSBram Moolenaar 			    lidx = list->lv_len + lidx;
18161cc2a94fSBram Moolenaar 			if (lidx < 0 || lidx > list->lv_len)
18171cc2a94fSBram Moolenaar 			{
18181cc2a94fSBram Moolenaar 			    semsg(_(e_listidx), lidx);
1819e859312eSBram Moolenaar 			    goto on_error;
18201cc2a94fSBram Moolenaar 			}
18211cc2a94fSBram Moolenaar 			if (lidx < list->lv_len)
18221cc2a94fSBram Moolenaar 			{
18231cc2a94fSBram Moolenaar 			    listitem_T *li = list_find(list, lidx);
18241cc2a94fSBram Moolenaar 
18250b4c66c6SBram Moolenaar 			    if (error_if_locked(li->li_tv.v_lock,
18260b4c66c6SBram Moolenaar 						    e_cannot_change_list_item))
18274f5e3977SBram Moolenaar 				goto on_error;
18281cc2a94fSBram Moolenaar 			    // overwrite existing list item
18291cc2a94fSBram Moolenaar 			    clear_tv(&li->li_tv);
18301cc2a94fSBram Moolenaar 			    li->li_tv = *tv;
18311cc2a94fSBram Moolenaar 			}
18321cc2a94fSBram Moolenaar 			else
18331cc2a94fSBram Moolenaar 			{
18340b4c66c6SBram Moolenaar 			    if (error_if_locked(list->lv_lock,
18350b4c66c6SBram Moolenaar 							 e_cannot_change_list))
18364f5e3977SBram Moolenaar 				goto on_error;
1837e859312eSBram Moolenaar 			    // append to list, only fails when out of memory
18381cc2a94fSBram Moolenaar 			    if (list_append_tv(list, tv) == FAIL)
18391cc2a94fSBram Moolenaar 				goto failed;
18401cc2a94fSBram Moolenaar 			    clear_tv(tv);
18411cc2a94fSBram Moolenaar 			}
18421cc2a94fSBram Moolenaar 		    }
18434f5e3977SBram Moolenaar 		    else if (status == OK && dest_type == VAR_DICT)
18441cc2a94fSBram Moolenaar 		    {
18454f5e3977SBram Moolenaar 			char_u		*key = tv_idx->vval.v_string;
18464f5e3977SBram Moolenaar 			dict_T		*dict = tv_dest->vval.v_dict;
18471cc2a94fSBram Moolenaar 			dictitem_T	*di;
18481cc2a94fSBram Moolenaar 
18490b4c66c6SBram Moolenaar 			SOURCING_LNUM = iptr->isn_lnum;
18508e4c8c85SBram Moolenaar 			if (dict == NULL)
18518e4c8c85SBram Moolenaar 			{
1852bc4c5051SBram Moolenaar 			    emsg(_(e_dictionary_not_set));
18538e4c8c85SBram Moolenaar 			    goto on_error;
18548e4c8c85SBram Moolenaar 			}
185558626872SBram Moolenaar 			if (key == NULL)
185658626872SBram Moolenaar 			    key = (char_u *)"";
18571cc2a94fSBram Moolenaar 			di = dict_find(dict, key, -1);
18581cc2a94fSBram Moolenaar 			if (di != NULL)
18591cc2a94fSBram Moolenaar 			{
18600b4c66c6SBram Moolenaar 			    if (error_if_locked(di->di_tv.v_lock,
18610b4c66c6SBram Moolenaar 						    e_cannot_change_dict_item))
18624f5e3977SBram Moolenaar 				goto on_error;
1863e859312eSBram Moolenaar 			    // overwrite existing value
18641cc2a94fSBram Moolenaar 			    clear_tv(&di->di_tv);
18651cc2a94fSBram Moolenaar 			    di->di_tv = *tv;
18661cc2a94fSBram Moolenaar 			}
18671cc2a94fSBram Moolenaar 			else
18681cc2a94fSBram Moolenaar 			{
18690b4c66c6SBram Moolenaar 			    if (error_if_locked(dict->dv_lock,
18700b4c66c6SBram Moolenaar 							 e_cannot_change_dict))
18714f5e3977SBram Moolenaar 				goto on_error;
1872e859312eSBram Moolenaar 			    // add to dict, only fails when out of memory
18731cc2a94fSBram Moolenaar 			    if (dict_add_tv(dict, (char *)key, tv) == FAIL)
18741cc2a94fSBram Moolenaar 				goto failed;
18751cc2a94fSBram Moolenaar 			    clear_tv(tv);
18761cc2a94fSBram Moolenaar 			}
18774f5e3977SBram Moolenaar 		    }
18784f5e3977SBram Moolenaar 		    else
18794f5e3977SBram Moolenaar 		    {
18804f5e3977SBram Moolenaar 			status = FAIL;
18814f5e3977SBram Moolenaar 			semsg(_(e_cannot_index_str), vartype_name(dest_type));
18824f5e3977SBram Moolenaar 		    }
18834f5e3977SBram Moolenaar 
18844f5e3977SBram Moolenaar 		    clear_tv(tv_idx);
18854f5e3977SBram Moolenaar 		    clear_tv(tv_dest);
1886f163bd5eSBram Moolenaar 		    ectx.ec_stack.ga_len -= 3;
18874f5e3977SBram Moolenaar 		    if (status == FAIL)
18884f5e3977SBram Moolenaar 		    {
18894f5e3977SBram Moolenaar 			clear_tv(tv);
18904f5e3977SBram Moolenaar 			goto on_error;
18914f5e3977SBram Moolenaar 		    }
18921cc2a94fSBram Moolenaar 		}
18931cc2a94fSBram Moolenaar 		break;
18941cc2a94fSBram Moolenaar 
18958a7d6542SBram Moolenaar 	    // push constant
18968a7d6542SBram Moolenaar 	    case ISN_PUSHNR:
18978a7d6542SBram Moolenaar 	    case ISN_PUSHBOOL:
18988a7d6542SBram Moolenaar 	    case ISN_PUSHSPEC:
18998a7d6542SBram Moolenaar 	    case ISN_PUSHF:
19008a7d6542SBram Moolenaar 	    case ISN_PUSHS:
19018a7d6542SBram Moolenaar 	    case ISN_PUSHBLOB:
190242a480bfSBram Moolenaar 	    case ISN_PUSHFUNC:
190342a480bfSBram Moolenaar 	    case ISN_PUSHCHANNEL:
190442a480bfSBram Moolenaar 	    case ISN_PUSHJOB:
1905270d0388SBram Moolenaar 		if (GA_GROW(&ectx.ec_stack, 1) == FAIL)
19068a7d6542SBram Moolenaar 		    goto failed;
19078a7d6542SBram Moolenaar 		tv = STACK_TV_BOT(0);
19082f8ce0aeSBram Moolenaar 		tv->v_lock = 0;
19098a7d6542SBram Moolenaar 		++ectx.ec_stack.ga_len;
19108a7d6542SBram Moolenaar 		switch (iptr->isn_type)
19118a7d6542SBram Moolenaar 		{
19128a7d6542SBram Moolenaar 		    case ISN_PUSHNR:
19138a7d6542SBram Moolenaar 			tv->v_type = VAR_NUMBER;
19148a7d6542SBram Moolenaar 			tv->vval.v_number = iptr->isn_arg.number;
19158a7d6542SBram Moolenaar 			break;
19168a7d6542SBram Moolenaar 		    case ISN_PUSHBOOL:
19178a7d6542SBram Moolenaar 			tv->v_type = VAR_BOOL;
19188a7d6542SBram Moolenaar 			tv->vval.v_number = iptr->isn_arg.number;
19198a7d6542SBram Moolenaar 			break;
19208a7d6542SBram Moolenaar 		    case ISN_PUSHSPEC:
19218a7d6542SBram Moolenaar 			tv->v_type = VAR_SPECIAL;
19228a7d6542SBram Moolenaar 			tv->vval.v_number = iptr->isn_arg.number;
19238a7d6542SBram Moolenaar 			break;
19248a7d6542SBram Moolenaar #ifdef FEAT_FLOAT
19258a7d6542SBram Moolenaar 		    case ISN_PUSHF:
19268a7d6542SBram Moolenaar 			tv->v_type = VAR_FLOAT;
19278a7d6542SBram Moolenaar 			tv->vval.v_float = iptr->isn_arg.fnumber;
19288a7d6542SBram Moolenaar 			break;
19298a7d6542SBram Moolenaar #endif
19308a7d6542SBram Moolenaar 		    case ISN_PUSHBLOB:
19318a7d6542SBram Moolenaar 			blob_copy(iptr->isn_arg.blob, tv);
19328a7d6542SBram Moolenaar 			break;
193342a480bfSBram Moolenaar 		    case ISN_PUSHFUNC:
193442a480bfSBram Moolenaar 			tv->v_type = VAR_FUNC;
1935087d2e15SBram Moolenaar 			if (iptr->isn_arg.string == NULL)
1936087d2e15SBram Moolenaar 			    tv->vval.v_string = NULL;
1937087d2e15SBram Moolenaar 			else
1938087d2e15SBram Moolenaar 			    tv->vval.v_string =
1939087d2e15SBram Moolenaar 					     vim_strsave(iptr->isn_arg.string);
194042a480bfSBram Moolenaar 			break;
194142a480bfSBram Moolenaar 		    case ISN_PUSHCHANNEL:
194242a480bfSBram Moolenaar #ifdef FEAT_JOB_CHANNEL
194342a480bfSBram Moolenaar 			tv->v_type = VAR_CHANNEL;
194442a480bfSBram Moolenaar 			tv->vval.v_channel = iptr->isn_arg.channel;
194542a480bfSBram Moolenaar 			if (tv->vval.v_channel != NULL)
194642a480bfSBram Moolenaar 			    ++tv->vval.v_channel->ch_refcount;
194742a480bfSBram Moolenaar #endif
194842a480bfSBram Moolenaar 			break;
194942a480bfSBram Moolenaar 		    case ISN_PUSHJOB:
195042a480bfSBram Moolenaar #ifdef FEAT_JOB_CHANNEL
195142a480bfSBram Moolenaar 			tv->v_type = VAR_JOB;
195242a480bfSBram Moolenaar 			tv->vval.v_job = iptr->isn_arg.job;
195342a480bfSBram Moolenaar 			if (tv->vval.v_job != NULL)
195442a480bfSBram Moolenaar 			    ++tv->vval.v_job->jv_refcount;
195542a480bfSBram Moolenaar #endif
195642a480bfSBram Moolenaar 			break;
19578a7d6542SBram Moolenaar 		    default:
19588a7d6542SBram Moolenaar 			tv->v_type = VAR_STRING;
1959e69f6d04SBram Moolenaar 			tv->vval.v_string = vim_strsave(
1960e69f6d04SBram Moolenaar 				iptr->isn_arg.string == NULL
1961e69f6d04SBram Moolenaar 					? (char_u *)"" : iptr->isn_arg.string);
19628a7d6542SBram Moolenaar 		}
19638a7d6542SBram Moolenaar 		break;
19648a7d6542SBram Moolenaar 
1965d72c1bf0SBram Moolenaar 	    case ISN_UNLET:
1966d72c1bf0SBram Moolenaar 		if (do_unlet(iptr->isn_arg.unlet.ul_name,
1967d72c1bf0SBram Moolenaar 				       iptr->isn_arg.unlet.ul_forceit) == FAIL)
1968e859312eSBram Moolenaar 		    goto on_error;
1969d72c1bf0SBram Moolenaar 		break;
19707bdaea6eSBram Moolenaar 	    case ISN_UNLETENV:
19717bdaea6eSBram Moolenaar 		vim_unsetenv(iptr->isn_arg.unlet.ul_name);
19727bdaea6eSBram Moolenaar 		break;
1973d72c1bf0SBram Moolenaar 
19740b4c66c6SBram Moolenaar 	    case ISN_LOCKCONST:
19750b4c66c6SBram Moolenaar 		item_lock(STACK_TV_BOT(-1), 100, TRUE, TRUE);
19760b4c66c6SBram Moolenaar 		break;
19770b4c66c6SBram Moolenaar 
19788a7d6542SBram Moolenaar 	    // create a list from items on the stack; uses a single allocation
19798a7d6542SBram Moolenaar 	    // for the list header and the items
19808a7d6542SBram Moolenaar 	    case ISN_NEWLIST:
1981fe270817SBram Moolenaar 		if (exe_newlist(iptr->isn_arg.number, &ectx) == FAIL)
19828a7d6542SBram Moolenaar 		    goto failed;
19838a7d6542SBram Moolenaar 		break;
19848a7d6542SBram Moolenaar 
19858a7d6542SBram Moolenaar 	    // create a dict from items on the stack
19868a7d6542SBram Moolenaar 	    case ISN_NEWDICT:
19878a7d6542SBram Moolenaar 		{
19888a7d6542SBram Moolenaar 		    int		count = iptr->isn_arg.number;
19898a7d6542SBram Moolenaar 		    dict_T	*dict = dict_alloc();
19908a7d6542SBram Moolenaar 		    dictitem_T	*item;
1991c7f7f6dbSBram Moolenaar 		    char_u	*key;
19928a7d6542SBram Moolenaar 
19938a7d6542SBram Moolenaar 		    if (dict == NULL)
19948a7d6542SBram Moolenaar 			goto failed;
19958a7d6542SBram Moolenaar 		    for (idx = 0; idx < count; ++idx)
19968a7d6542SBram Moolenaar 		    {
1997e859312eSBram Moolenaar 			// have already checked key type is VAR_STRING
19988a7d6542SBram Moolenaar 			tv = STACK_TV_BOT(2 * (idx - count));
1999e859312eSBram Moolenaar 			// check key is unique
2000c7f7f6dbSBram Moolenaar 			key = tv->vval.v_string == NULL
2001c7f7f6dbSBram Moolenaar 					    ? (char_u *)"" : tv->vval.v_string;
2002c7f7f6dbSBram Moolenaar 			item = dict_find(dict, key, -1);
2003e859312eSBram Moolenaar 			if (item != NULL)
2004e859312eSBram Moolenaar 			{
20057517ffdbSBram Moolenaar 			    SOURCING_LNUM = iptr->isn_lnum;
2006c7f7f6dbSBram Moolenaar 			    semsg(_(e_duplicate_key), key);
2007e859312eSBram Moolenaar 			    dict_unref(dict);
2008e859312eSBram Moolenaar 			    goto on_error;
2009e859312eSBram Moolenaar 			}
2010c7f7f6dbSBram Moolenaar 			item = dictitem_alloc(key);
20118a7d6542SBram Moolenaar 			clear_tv(tv);
20128a7d6542SBram Moolenaar 			if (item == NULL)
2013e859312eSBram Moolenaar 			{
2014e859312eSBram Moolenaar 			    dict_unref(dict);
20158a7d6542SBram Moolenaar 			    goto failed;
2016e859312eSBram Moolenaar 			}
20178a7d6542SBram Moolenaar 			item->di_tv = *STACK_TV_BOT(2 * (idx - count) + 1);
20188a7d6542SBram Moolenaar 			item->di_tv.v_lock = 0;
20198a7d6542SBram Moolenaar 			if (dict_add(dict, item) == FAIL)
2020e859312eSBram Moolenaar 			{
2021d032f34aSBram Moolenaar 			    // can this ever happen?
2022e859312eSBram Moolenaar 			    dict_unref(dict);
20238a7d6542SBram Moolenaar 			    goto failed;
20248a7d6542SBram Moolenaar 			}
2025e859312eSBram Moolenaar 		    }
20268a7d6542SBram Moolenaar 
20278a7d6542SBram Moolenaar 		    if (count > 0)
20288a7d6542SBram Moolenaar 			ectx.ec_stack.ga_len -= 2 * count - 1;
2029270d0388SBram Moolenaar 		    else if (GA_GROW(&ectx.ec_stack, 1) == FAIL)
20308a7d6542SBram Moolenaar 			goto failed;
20318a7d6542SBram Moolenaar 		    else
20328a7d6542SBram Moolenaar 			++ectx.ec_stack.ga_len;
20338a7d6542SBram Moolenaar 		    tv = STACK_TV_BOT(-1);
20348a7d6542SBram Moolenaar 		    tv->v_type = VAR_DICT;
20352f8ce0aeSBram Moolenaar 		    tv->v_lock = 0;
20368a7d6542SBram Moolenaar 		    tv->vval.v_dict = dict;
20378a7d6542SBram Moolenaar 		    ++dict->dv_refcount;
20388a7d6542SBram Moolenaar 		}
20398a7d6542SBram Moolenaar 		break;
20408a7d6542SBram Moolenaar 
20418a7d6542SBram Moolenaar 	    // call a :def function
20428a7d6542SBram Moolenaar 	    case ISN_DCALL:
2043dfa3d552SBram Moolenaar 		SOURCING_LNUM = iptr->isn_lnum;
20448a7d6542SBram Moolenaar 		if (call_dfunc(iptr->isn_arg.dfunc.cdf_idx,
20458a7d6542SBram Moolenaar 			      iptr->isn_arg.dfunc.cdf_argcount,
20468a7d6542SBram Moolenaar 			      &ectx) == FAIL)
2047e859312eSBram Moolenaar 		    goto on_error;
20488a7d6542SBram Moolenaar 		break;
20498a7d6542SBram Moolenaar 
20508a7d6542SBram Moolenaar 	    // call a builtin function
20518a7d6542SBram Moolenaar 	    case ISN_BCALL:
20528a7d6542SBram Moolenaar 		SOURCING_LNUM = iptr->isn_lnum;
20538a7d6542SBram Moolenaar 		if (call_bfunc(iptr->isn_arg.bfunc.cbf_idx,
20548a7d6542SBram Moolenaar 			      iptr->isn_arg.bfunc.cbf_argcount,
20558a7d6542SBram Moolenaar 			      &ectx) == FAIL)
2056d032f34aSBram Moolenaar 		    goto on_error;
20578a7d6542SBram Moolenaar 		break;
20588a7d6542SBram Moolenaar 
20598a7d6542SBram Moolenaar 	    // call a funcref or partial
20608a7d6542SBram Moolenaar 	    case ISN_PCALL:
20618a7d6542SBram Moolenaar 		{
20628a7d6542SBram Moolenaar 		    cpfunc_T	*pfunc = &iptr->isn_arg.pfunc;
20638a7d6542SBram Moolenaar 		    int		r;
20646f5b6dfbSBram Moolenaar 		    typval_T	partial_tv;
20658a7d6542SBram Moolenaar 
20668a7d6542SBram Moolenaar 		    SOURCING_LNUM = iptr->isn_lnum;
20678a7d6542SBram Moolenaar 		    if (pfunc->cpf_top)
20688a7d6542SBram Moolenaar 		    {
20698a7d6542SBram Moolenaar 			// funcref is above the arguments
20708a7d6542SBram Moolenaar 			tv = STACK_TV_BOT(-pfunc->cpf_argcount - 1);
20718a7d6542SBram Moolenaar 		    }
20728a7d6542SBram Moolenaar 		    else
20738a7d6542SBram Moolenaar 		    {
20748a7d6542SBram Moolenaar 			// Get the funcref from the stack.
20758a7d6542SBram Moolenaar 			--ectx.ec_stack.ga_len;
20766f5b6dfbSBram Moolenaar 			partial_tv = *STACK_TV_BOT(0);
20776f5b6dfbSBram Moolenaar 			tv = &partial_tv;
20788a7d6542SBram Moolenaar 		    }
20798a7d6542SBram Moolenaar 		    r = call_partial(tv, pfunc->cpf_argcount, &ectx);
20806f5b6dfbSBram Moolenaar 		    if (tv == &partial_tv)
20816f5b6dfbSBram Moolenaar 			clear_tv(&partial_tv);
20828a7d6542SBram Moolenaar 		    if (r == FAIL)
2083d032f34aSBram Moolenaar 			goto on_error;
2084bd5da371SBram Moolenaar 		}
2085bd5da371SBram Moolenaar 		break;
20868a7d6542SBram Moolenaar 
2087bd5da371SBram Moolenaar 	    case ISN_PCALL_END:
2088bd5da371SBram Moolenaar 		// PCALL finished, arguments have been consumed and replaced by
2089bd5da371SBram Moolenaar 		// the return value.  Now clear the funcref from the stack,
2090bd5da371SBram Moolenaar 		// and move the return value in its place.
20918a7d6542SBram Moolenaar 		--ectx.ec_stack.ga_len;
2092bd5da371SBram Moolenaar 		clear_tv(STACK_TV_BOT(-1));
20938a7d6542SBram Moolenaar 		*STACK_TV_BOT(-1) = *STACK_TV_BOT(0);
20948a7d6542SBram Moolenaar 		break;
20958a7d6542SBram Moolenaar 
20968a7d6542SBram Moolenaar 	    // call a user defined function or funcref/partial
20978a7d6542SBram Moolenaar 	    case ISN_UCALL:
20988a7d6542SBram Moolenaar 		{
20998a7d6542SBram Moolenaar 		    cufunc_T	*cufunc = &iptr->isn_arg.ufunc;
21008a7d6542SBram Moolenaar 
21018a7d6542SBram Moolenaar 		    SOURCING_LNUM = iptr->isn_lnum;
21028a7d6542SBram Moolenaar 		    if (call_eval_func(cufunc->cuf_name,
21037eeefd4aSBram Moolenaar 				    cufunc->cuf_argcount, &ectx, iptr) == FAIL)
2104d032f34aSBram Moolenaar 			goto on_error;
21058a7d6542SBram Moolenaar 		}
21068a7d6542SBram Moolenaar 		break;
21078a7d6542SBram Moolenaar 
21088a7d6542SBram Moolenaar 	    // return from a :def function call
21098a7d6542SBram Moolenaar 	    case ISN_RETURN:
21108a7d6542SBram Moolenaar 		{
21118cbd6dfcSBram Moolenaar 		    garray_T	*trystack = &ectx.ec_trystack;
211220431c9dSBram Moolenaar 		    trycmd_T    *trycmd = NULL;
21138cbd6dfcSBram Moolenaar 
21148cbd6dfcSBram Moolenaar 		    if (trystack->ga_len > 0)
21158cbd6dfcSBram Moolenaar 			trycmd = ((trycmd_T *)trystack->ga_data)
21168cbd6dfcSBram Moolenaar 							+ trystack->ga_len - 1;
2117bf67ea1aSBram Moolenaar 		    if (trycmd != NULL
2118bf67ea1aSBram Moolenaar 				  && trycmd->tcd_frame_idx == ectx.ec_frame_idx
21198a7d6542SBram Moolenaar 			    && trycmd->tcd_finally_idx != 0)
21208a7d6542SBram Moolenaar 		    {
21218a7d6542SBram Moolenaar 			// jump to ":finally"
21228a7d6542SBram Moolenaar 			ectx.ec_iidx = trycmd->tcd_finally_idx;
21238a7d6542SBram Moolenaar 			trycmd->tcd_return = TRUE;
21248a7d6542SBram Moolenaar 		    }
21258a7d6542SBram Moolenaar 		    else
2126d032f34aSBram Moolenaar 			goto func_return;
21278a7d6542SBram Moolenaar 		}
21288a7d6542SBram Moolenaar 		break;
21298a7d6542SBram Moolenaar 
21308a7d6542SBram Moolenaar 	    // push a function reference to a compiled function
21318a7d6542SBram Moolenaar 	    case ISN_FUNCREF:
21328a7d6542SBram Moolenaar 		{
2133f112f30aSBram Moolenaar 		    partial_T   *pt = ALLOC_CLEAR_ONE(partial_T);
2134f112f30aSBram Moolenaar 		    dfunc_T	*pt_dfunc = ((dfunc_T *)def_functions.ga_data)
2135f112f30aSBram Moolenaar 					       + iptr->isn_arg.funcref.fr_func;
21368a7d6542SBram Moolenaar 
21378a7d6542SBram Moolenaar 		    if (pt == NULL)
21388a7d6542SBram Moolenaar 			goto failed;
2139270d0388SBram Moolenaar 		    if (GA_GROW(&ectx.ec_stack, 1) == FAIL)
2140c8cd2b34SBram Moolenaar 		    {
2141bf67ea1aSBram Moolenaar 			vim_free(pt);
2142bf67ea1aSBram Moolenaar 			goto failed;
2143bf67ea1aSBram Moolenaar 		    }
2144f112f30aSBram Moolenaar 		    if (fill_partial_and_closure(pt, pt_dfunc->df_ufunc,
2145f112f30aSBram Moolenaar 								&ectx) == FAIL)
2146bf67ea1aSBram Moolenaar 			goto failed;
2147c8cd2b34SBram Moolenaar 
21488a7d6542SBram Moolenaar 		    tv = STACK_TV_BOT(0);
21498a7d6542SBram Moolenaar 		    ++ectx.ec_stack.ga_len;
21508a7d6542SBram Moolenaar 		    tv->vval.v_partial = pt;
21518a7d6542SBram Moolenaar 		    tv->v_type = VAR_PARTIAL;
21522f8ce0aeSBram Moolenaar 		    tv->v_lock = 0;
21538a7d6542SBram Moolenaar 		}
21548a7d6542SBram Moolenaar 		break;
21558a7d6542SBram Moolenaar 
215638ddf333SBram Moolenaar 	    // Create a global function from a lambda.
215738ddf333SBram Moolenaar 	    case ISN_NEWFUNC:
215838ddf333SBram Moolenaar 		{
215938ddf333SBram Moolenaar 		    newfunc_T	*newfunc = &iptr->isn_arg.newfunc;
216038ddf333SBram Moolenaar 
2161cd45ed03SBram Moolenaar 		    if (copy_func(newfunc->nf_lambda, newfunc->nf_global,
2162f112f30aSBram Moolenaar 								&ectx) == FAIL)
2163f112f30aSBram Moolenaar 			goto failed;
216438ddf333SBram Moolenaar 		}
216538ddf333SBram Moolenaar 		break;
216638ddf333SBram Moolenaar 
21676abdcf82SBram Moolenaar 	    // List functions
21686abdcf82SBram Moolenaar 	    case ISN_DEF:
21696abdcf82SBram Moolenaar 		if (iptr->isn_arg.string == NULL)
21706abdcf82SBram Moolenaar 		    list_functions(NULL);
21716abdcf82SBram Moolenaar 		else
21726abdcf82SBram Moolenaar 		{
21736abdcf82SBram Moolenaar 		    exarg_T ea;
21746abdcf82SBram Moolenaar 
21756abdcf82SBram Moolenaar 		    CLEAR_FIELD(ea);
21766abdcf82SBram Moolenaar 		    ea.cmd = ea.arg = iptr->isn_arg.string;
21776abdcf82SBram Moolenaar 		    define_function(&ea, NULL);
21786abdcf82SBram Moolenaar 		}
21796abdcf82SBram Moolenaar 		break;
21806abdcf82SBram Moolenaar 
21818a7d6542SBram Moolenaar 	    // jump if a condition is met
21828a7d6542SBram Moolenaar 	    case ISN_JUMP:
21838a7d6542SBram Moolenaar 		{
21848a7d6542SBram Moolenaar 		    jumpwhen_T	when = iptr->isn_arg.jump.jump_when;
21852bb2658bSBram Moolenaar 		    int		error = FALSE;
21868a7d6542SBram Moolenaar 		    int		jump = TRUE;
21878a7d6542SBram Moolenaar 
21888a7d6542SBram Moolenaar 		    if (when != JUMP_ALWAYS)
21898a7d6542SBram Moolenaar 		    {
21908a7d6542SBram Moolenaar 			tv = STACK_TV_BOT(-1);
21912bb2658bSBram Moolenaar 			if (when == JUMP_IF_COND_FALSE
219213106605SBram Moolenaar 				|| when == JUMP_IF_FALSE
21932bb2658bSBram Moolenaar 				|| when == JUMP_IF_COND_TRUE)
21942bb2658bSBram Moolenaar 			{
21952bb2658bSBram Moolenaar 			    SOURCING_LNUM = iptr->isn_lnum;
21962bb2658bSBram Moolenaar 			    jump = tv_get_bool_chk(tv, &error);
21972bb2658bSBram Moolenaar 			    if (error)
21982bb2658bSBram Moolenaar 				goto on_error;
21992bb2658bSBram Moolenaar 			}
22002bb2658bSBram Moolenaar 			else
22018a7d6542SBram Moolenaar 			    jump = tv2bool(tv);
22028a7d6542SBram Moolenaar 			if (when == JUMP_IF_FALSE
22032bb2658bSBram Moolenaar 					     || when == JUMP_AND_KEEP_IF_FALSE
22042bb2658bSBram Moolenaar 					     || when == JUMP_IF_COND_FALSE)
22058a7d6542SBram Moolenaar 			    jump = !jump;
2206777770fbSBram Moolenaar 			if (when == JUMP_IF_FALSE || !jump)
22078a7d6542SBram Moolenaar 			{
22088a7d6542SBram Moolenaar 			    // drop the value from the stack
22098a7d6542SBram Moolenaar 			    clear_tv(tv);
22108a7d6542SBram Moolenaar 			    --ectx.ec_stack.ga_len;
22118a7d6542SBram Moolenaar 			}
22128a7d6542SBram Moolenaar 		    }
22138a7d6542SBram Moolenaar 		    if (jump)
22148a7d6542SBram Moolenaar 			ectx.ec_iidx = iptr->isn_arg.jump.jump_where;
22158a7d6542SBram Moolenaar 		}
22168a7d6542SBram Moolenaar 		break;
22178a7d6542SBram Moolenaar 
22188a7d6542SBram Moolenaar 	    // top of a for loop
22198a7d6542SBram Moolenaar 	    case ISN_FOR:
22208a7d6542SBram Moolenaar 		{
22218a7d6542SBram Moolenaar 		    list_T	*list = STACK_TV_BOT(-1)->vval.v_list;
22228a7d6542SBram Moolenaar 		    typval_T	*idxtv =
22238a7d6542SBram Moolenaar 				   STACK_TV_VAR(iptr->isn_arg.forloop.for_idx);
22248a7d6542SBram Moolenaar 
22258a7d6542SBram Moolenaar 		    // push the next item from the list
2226270d0388SBram Moolenaar 		    if (GA_GROW(&ectx.ec_stack, 1) == FAIL)
22278a7d6542SBram Moolenaar 			goto failed;
222877e5dcc3SBram Moolenaar 		    ++idxtv->vval.v_number;
222977e5dcc3SBram Moolenaar 		    if (list == NULL || idxtv->vval.v_number >= list->lv_len)
22308a7d6542SBram Moolenaar 			// past the end of the list, jump to "endfor"
22318a7d6542SBram Moolenaar 			ectx.ec_iidx = iptr->isn_arg.forloop.for_end;
22328a7d6542SBram Moolenaar 		    else if (list->lv_first == &range_list_item)
22338a7d6542SBram Moolenaar 		    {
22348a7d6542SBram Moolenaar 			// non-materialized range() list
22358a7d6542SBram Moolenaar 			tv = STACK_TV_BOT(0);
22368a7d6542SBram Moolenaar 			tv->v_type = VAR_NUMBER;
22372f8ce0aeSBram Moolenaar 			tv->v_lock = 0;
22388a7d6542SBram Moolenaar 			tv->vval.v_number = list_find_nr(
22398a7d6542SBram Moolenaar 					     list, idxtv->vval.v_number, NULL);
22408a7d6542SBram Moolenaar 			++ectx.ec_stack.ga_len;
22418a7d6542SBram Moolenaar 		    }
22428a7d6542SBram Moolenaar 		    else
22438a7d6542SBram Moolenaar 		    {
22448a7d6542SBram Moolenaar 			listitem_T *li = list_find(list, idxtv->vval.v_number);
22458a7d6542SBram Moolenaar 
22468a7d6542SBram Moolenaar 			copy_tv(&li->li_tv, STACK_TV_BOT(0));
22478a7d6542SBram Moolenaar 			++ectx.ec_stack.ga_len;
22488a7d6542SBram Moolenaar 		    }
22498a7d6542SBram Moolenaar 		}
22508a7d6542SBram Moolenaar 		break;
22518a7d6542SBram Moolenaar 
22528a7d6542SBram Moolenaar 	    // start of ":try" block
22538a7d6542SBram Moolenaar 	    case ISN_TRY:
22548a7d6542SBram Moolenaar 		{
225520431c9dSBram Moolenaar 		    trycmd_T    *trycmd = NULL;
225620431c9dSBram Moolenaar 
2257270d0388SBram Moolenaar 		    if (GA_GROW(&ectx.ec_trystack, 1) == FAIL)
22588a7d6542SBram Moolenaar 			goto failed;
22598a7d6542SBram Moolenaar 		    trycmd = ((trycmd_T *)ectx.ec_trystack.ga_data)
22608a7d6542SBram Moolenaar 						     + ectx.ec_trystack.ga_len;
22618a7d6542SBram Moolenaar 		    ++ectx.ec_trystack.ga_len;
22628a7d6542SBram Moolenaar 		    ++trylevel;
2263bf67ea1aSBram Moolenaar 		    trycmd->tcd_frame_idx = ectx.ec_frame_idx;
22648a7d6542SBram Moolenaar 		    trycmd->tcd_catch_idx = iptr->isn_arg.try.try_catch;
22658a7d6542SBram Moolenaar 		    trycmd->tcd_finally_idx = iptr->isn_arg.try.try_finally;
2266f575adffSBram Moolenaar 		    trycmd->tcd_caught = FALSE;
22679939f57bSBram Moolenaar 		    trycmd->tcd_return = FALSE;
22688a7d6542SBram Moolenaar 		}
22698a7d6542SBram Moolenaar 		break;
22708a7d6542SBram Moolenaar 
22718a7d6542SBram Moolenaar 	    case ISN_PUSHEXC:
22728a7d6542SBram Moolenaar 		if (current_exception == NULL)
22738a7d6542SBram Moolenaar 		{
22747517ffdbSBram Moolenaar 		    SOURCING_LNUM = iptr->isn_lnum;
22758a7d6542SBram Moolenaar 		    iemsg("Evaluating catch while current_exception is NULL");
22768a7d6542SBram Moolenaar 		    goto failed;
22778a7d6542SBram Moolenaar 		}
2278270d0388SBram Moolenaar 		if (GA_GROW(&ectx.ec_stack, 1) == FAIL)
22798a7d6542SBram Moolenaar 		    goto failed;
22808a7d6542SBram Moolenaar 		tv = STACK_TV_BOT(0);
22818a7d6542SBram Moolenaar 		++ectx.ec_stack.ga_len;
22828a7d6542SBram Moolenaar 		tv->v_type = VAR_STRING;
22832f8ce0aeSBram Moolenaar 		tv->v_lock = 0;
22848a7d6542SBram Moolenaar 		tv->vval.v_string = vim_strsave(
22858a7d6542SBram Moolenaar 					   (char_u *)current_exception->value);
22868a7d6542SBram Moolenaar 		break;
22878a7d6542SBram Moolenaar 
22888a7d6542SBram Moolenaar 	    case ISN_CATCH:
22898a7d6542SBram Moolenaar 		{
22908a7d6542SBram Moolenaar 		    garray_T	*trystack = &ectx.ec_trystack;
22918a7d6542SBram Moolenaar 
229220a76298SBram Moolenaar 		    if (restore_cmdmod)
229320a76298SBram Moolenaar 		    {
229420a76298SBram Moolenaar 			cmdmod.cmod_filter_regmatch.regprog = NULL;
229520a76298SBram Moolenaar 			undo_cmdmod(&cmdmod);
229620a76298SBram Moolenaar 			cmdmod = save_cmdmod;
229720a76298SBram Moolenaar 			restore_cmdmod = FALSE;
229820a76298SBram Moolenaar 		    }
22998a7d6542SBram Moolenaar 		    if (trystack->ga_len > 0)
23008a7d6542SBram Moolenaar 		    {
230120431c9dSBram Moolenaar 			trycmd_T    *trycmd = ((trycmd_T *)trystack->ga_data)
23028a7d6542SBram Moolenaar 							+ trystack->ga_len - 1;
23038a7d6542SBram Moolenaar 			trycmd->tcd_caught = TRUE;
23048a7d6542SBram Moolenaar 		    }
23058a7d6542SBram Moolenaar 		    did_emsg = got_int = did_throw = FALSE;
23068a7d6542SBram Moolenaar 		    catch_exception(current_exception);
23078a7d6542SBram Moolenaar 		}
23088a7d6542SBram Moolenaar 		break;
23098a7d6542SBram Moolenaar 
23108a7d6542SBram Moolenaar 	    // end of ":try" block
23118a7d6542SBram Moolenaar 	    case ISN_ENDTRY:
23128a7d6542SBram Moolenaar 		{
23138a7d6542SBram Moolenaar 		    garray_T	*trystack = &ectx.ec_trystack;
23148a7d6542SBram Moolenaar 
23158a7d6542SBram Moolenaar 		    if (trystack->ga_len > 0)
23168a7d6542SBram Moolenaar 		    {
231720431c9dSBram Moolenaar 			trycmd_T    *trycmd = NULL;
231820431c9dSBram Moolenaar 
23198a7d6542SBram Moolenaar 			--trystack->ga_len;
23208a7d6542SBram Moolenaar 			--trylevel;
232168d130c6SBram Moolenaar 			ectx.ec_in_catch = FALSE;
23228a7d6542SBram Moolenaar 			trycmd = ((trycmd_T *)trystack->ga_data)
23238a7d6542SBram Moolenaar 							    + trystack->ga_len;
2324f575adffSBram Moolenaar 			if (trycmd->tcd_caught && current_exception != NULL)
23258a7d6542SBram Moolenaar 			{
23268a7d6542SBram Moolenaar 			    // discard the exception
23278a7d6542SBram Moolenaar 			    if (caught_stack == current_exception)
23288a7d6542SBram Moolenaar 				caught_stack = caught_stack->caught;
23298a7d6542SBram Moolenaar 			    discard_current_exception();
23308a7d6542SBram Moolenaar 			}
23318a7d6542SBram Moolenaar 
23328a7d6542SBram Moolenaar 			if (trycmd->tcd_return)
2333d032f34aSBram Moolenaar 			    goto func_return;
23348a7d6542SBram Moolenaar 		    }
23358a7d6542SBram Moolenaar 		}
23368a7d6542SBram Moolenaar 		break;
23378a7d6542SBram Moolenaar 
23388a7d6542SBram Moolenaar 	    case ISN_THROW:
23398a7d6542SBram Moolenaar 		--ectx.ec_stack.ga_len;
23408a7d6542SBram Moolenaar 		tv = STACK_TV_BOT(0);
23411e021e63SBram Moolenaar 		if (tv->vval.v_string == NULL
23421e021e63SBram Moolenaar 				       || *skipwhite(tv->vval.v_string) == NUL)
23431e021e63SBram Moolenaar 		{
2344335e6713SBram Moolenaar 		    vim_free(tv->vval.v_string);
23451dcae599SBram Moolenaar 		    SOURCING_LNUM = iptr->isn_lnum;
23461e021e63SBram Moolenaar 		    emsg(_(e_throw_with_empty_string));
23471e021e63SBram Moolenaar 		    goto failed;
23481e021e63SBram Moolenaar 		}
23491e021e63SBram Moolenaar 
23508a7d6542SBram Moolenaar 		if (throw_exception(tv->vval.v_string, ET_USER, NULL) == FAIL)
23518a7d6542SBram Moolenaar 		{
23528a7d6542SBram Moolenaar 		    vim_free(tv->vval.v_string);
23538a7d6542SBram Moolenaar 		    goto failed;
23548a7d6542SBram Moolenaar 		}
23558a7d6542SBram Moolenaar 		did_throw = TRUE;
23568a7d6542SBram Moolenaar 		break;
23578a7d6542SBram Moolenaar 
23588a7d6542SBram Moolenaar 	    // compare with special values
23598a7d6542SBram Moolenaar 	    case ISN_COMPAREBOOL:
23608a7d6542SBram Moolenaar 	    case ISN_COMPARESPECIAL:
23618a7d6542SBram Moolenaar 		{
23628a7d6542SBram Moolenaar 		    typval_T	*tv1 = STACK_TV_BOT(-2);
23638a7d6542SBram Moolenaar 		    typval_T	*tv2 = STACK_TV_BOT(-1);
23648a7d6542SBram Moolenaar 		    varnumber_T arg1 = tv1->vval.v_number;
23658a7d6542SBram Moolenaar 		    varnumber_T arg2 = tv2->vval.v_number;
23668a7d6542SBram Moolenaar 		    int		res;
23678a7d6542SBram Moolenaar 
23688a7d6542SBram Moolenaar 		    switch (iptr->isn_arg.op.op_type)
23698a7d6542SBram Moolenaar 		    {
23708a7d6542SBram Moolenaar 			case EXPR_EQUAL: res = arg1 == arg2; break;
23718a7d6542SBram Moolenaar 			case EXPR_NEQUAL: res = arg1 != arg2; break;
23728a7d6542SBram Moolenaar 			default: res = 0; break;
23738a7d6542SBram Moolenaar 		    }
23748a7d6542SBram Moolenaar 
23758a7d6542SBram Moolenaar 		    --ectx.ec_stack.ga_len;
23768a7d6542SBram Moolenaar 		    tv1->v_type = VAR_BOOL;
23778a7d6542SBram Moolenaar 		    tv1->vval.v_number = res ? VVAL_TRUE : VVAL_FALSE;
23788a7d6542SBram Moolenaar 		}
23798a7d6542SBram Moolenaar 		break;
23808a7d6542SBram Moolenaar 
23818a7d6542SBram Moolenaar 	    // Operation with two number arguments
23828a7d6542SBram Moolenaar 	    case ISN_OPNR:
23838a7d6542SBram Moolenaar 	    case ISN_COMPARENR:
23848a7d6542SBram Moolenaar 		{
23858a7d6542SBram Moolenaar 		    typval_T	*tv1 = STACK_TV_BOT(-2);
23868a7d6542SBram Moolenaar 		    typval_T	*tv2 = STACK_TV_BOT(-1);
23878a7d6542SBram Moolenaar 		    varnumber_T arg1 = tv1->vval.v_number;
23888a7d6542SBram Moolenaar 		    varnumber_T arg2 = tv2->vval.v_number;
23898a7d6542SBram Moolenaar 		    varnumber_T res;
23908a7d6542SBram Moolenaar 
23918a7d6542SBram Moolenaar 		    switch (iptr->isn_arg.op.op_type)
23928a7d6542SBram Moolenaar 		    {
23938a7d6542SBram Moolenaar 			case EXPR_MULT: res = arg1 * arg2; break;
23948a7d6542SBram Moolenaar 			case EXPR_DIV: res = arg1 / arg2; break;
23958a7d6542SBram Moolenaar 			case EXPR_REM: res = arg1 % arg2; break;
23968a7d6542SBram Moolenaar 			case EXPR_SUB: res = arg1 - arg2; break;
23978a7d6542SBram Moolenaar 			case EXPR_ADD: res = arg1 + arg2; break;
23988a7d6542SBram Moolenaar 
23998a7d6542SBram Moolenaar 			case EXPR_EQUAL: res = arg1 == arg2; break;
24008a7d6542SBram Moolenaar 			case EXPR_NEQUAL: res = arg1 != arg2; break;
24018a7d6542SBram Moolenaar 			case EXPR_GREATER: res = arg1 > arg2; break;
24028a7d6542SBram Moolenaar 			case EXPR_GEQUAL: res = arg1 >= arg2; break;
24038a7d6542SBram Moolenaar 			case EXPR_SMALLER: res = arg1 < arg2; break;
24048a7d6542SBram Moolenaar 			case EXPR_SEQUAL: res = arg1 <= arg2; break;
24058a7d6542SBram Moolenaar 			default: res = 0; break;
24068a7d6542SBram Moolenaar 		    }
24078a7d6542SBram Moolenaar 
24088a7d6542SBram Moolenaar 		    --ectx.ec_stack.ga_len;
24098a7d6542SBram Moolenaar 		    if (iptr->isn_type == ISN_COMPARENR)
24108a7d6542SBram Moolenaar 		    {
24118a7d6542SBram Moolenaar 			tv1->v_type = VAR_BOOL;
24128a7d6542SBram Moolenaar 			tv1->vval.v_number = res ? VVAL_TRUE : VVAL_FALSE;
24138a7d6542SBram Moolenaar 		    }
24148a7d6542SBram Moolenaar 		    else
24158a7d6542SBram Moolenaar 			tv1->vval.v_number = res;
24168a7d6542SBram Moolenaar 		}
24178a7d6542SBram Moolenaar 		break;
24188a7d6542SBram Moolenaar 
24198a7d6542SBram Moolenaar 	    // Computation with two float arguments
24208a7d6542SBram Moolenaar 	    case ISN_OPFLOAT:
24218a7d6542SBram Moolenaar 	    case ISN_COMPAREFLOAT:
2422a5d5953dSBram Moolenaar #ifdef FEAT_FLOAT
24238a7d6542SBram Moolenaar 		{
24248a7d6542SBram Moolenaar 		    typval_T	*tv1 = STACK_TV_BOT(-2);
24258a7d6542SBram Moolenaar 		    typval_T	*tv2 = STACK_TV_BOT(-1);
24268a7d6542SBram Moolenaar 		    float_T	arg1 = tv1->vval.v_float;
24278a7d6542SBram Moolenaar 		    float_T	arg2 = tv2->vval.v_float;
24288a7d6542SBram Moolenaar 		    float_T	res = 0;
24298a7d6542SBram Moolenaar 		    int		cmp = FALSE;
24308a7d6542SBram Moolenaar 
24318a7d6542SBram Moolenaar 		    switch (iptr->isn_arg.op.op_type)
24328a7d6542SBram Moolenaar 		    {
24338a7d6542SBram Moolenaar 			case EXPR_MULT: res = arg1 * arg2; break;
24348a7d6542SBram Moolenaar 			case EXPR_DIV: res = arg1 / arg2; break;
24358a7d6542SBram Moolenaar 			case EXPR_SUB: res = arg1 - arg2; break;
24368a7d6542SBram Moolenaar 			case EXPR_ADD: res = arg1 + arg2; break;
24378a7d6542SBram Moolenaar 
24388a7d6542SBram Moolenaar 			case EXPR_EQUAL: cmp = arg1 == arg2; break;
24398a7d6542SBram Moolenaar 			case EXPR_NEQUAL: cmp = arg1 != arg2; break;
24408a7d6542SBram Moolenaar 			case EXPR_GREATER: cmp = arg1 > arg2; break;
24418a7d6542SBram Moolenaar 			case EXPR_GEQUAL: cmp = arg1 >= arg2; break;
24428a7d6542SBram Moolenaar 			case EXPR_SMALLER: cmp = arg1 < arg2; break;
24438a7d6542SBram Moolenaar 			case EXPR_SEQUAL: cmp = arg1 <= arg2; break;
24448a7d6542SBram Moolenaar 			default: cmp = 0; break;
24458a7d6542SBram Moolenaar 		    }
24468a7d6542SBram Moolenaar 		    --ectx.ec_stack.ga_len;
24478a7d6542SBram Moolenaar 		    if (iptr->isn_type == ISN_COMPAREFLOAT)
24488a7d6542SBram Moolenaar 		    {
24498a7d6542SBram Moolenaar 			tv1->v_type = VAR_BOOL;
24508a7d6542SBram Moolenaar 			tv1->vval.v_number = cmp ? VVAL_TRUE : VVAL_FALSE;
24518a7d6542SBram Moolenaar 		    }
24528a7d6542SBram Moolenaar 		    else
24538a7d6542SBram Moolenaar 			tv1->vval.v_float = res;
24548a7d6542SBram Moolenaar 		}
2455a5d5953dSBram Moolenaar #endif
24568a7d6542SBram Moolenaar 		break;
24578a7d6542SBram Moolenaar 
24588a7d6542SBram Moolenaar 	    case ISN_COMPARELIST:
24598a7d6542SBram Moolenaar 		{
24608a7d6542SBram Moolenaar 		    typval_T	*tv1 = STACK_TV_BOT(-2);
24618a7d6542SBram Moolenaar 		    typval_T	*tv2 = STACK_TV_BOT(-1);
24628a7d6542SBram Moolenaar 		    list_T	*arg1 = tv1->vval.v_list;
24638a7d6542SBram Moolenaar 		    list_T	*arg2 = tv2->vval.v_list;
24648a7d6542SBram Moolenaar 		    int		cmp = FALSE;
24658a7d6542SBram Moolenaar 		    int		ic = iptr->isn_arg.op.op_ic;
24668a7d6542SBram Moolenaar 
24678a7d6542SBram Moolenaar 		    switch (iptr->isn_arg.op.op_type)
24688a7d6542SBram Moolenaar 		    {
24698a7d6542SBram Moolenaar 			case EXPR_EQUAL: cmp =
24708a7d6542SBram Moolenaar 				      list_equal(arg1, arg2, ic, FALSE); break;
24718a7d6542SBram Moolenaar 			case EXPR_NEQUAL: cmp =
24728a7d6542SBram Moolenaar 				     !list_equal(arg1, arg2, ic, FALSE); break;
24738a7d6542SBram Moolenaar 			case EXPR_IS: cmp = arg1 == arg2; break;
24748a7d6542SBram Moolenaar 			case EXPR_ISNOT: cmp = arg1 != arg2; break;
24758a7d6542SBram Moolenaar 			default: cmp = 0; break;
24768a7d6542SBram Moolenaar 		    }
24778a7d6542SBram Moolenaar 		    --ectx.ec_stack.ga_len;
24788a7d6542SBram Moolenaar 		    clear_tv(tv1);
24798a7d6542SBram Moolenaar 		    clear_tv(tv2);
24808a7d6542SBram Moolenaar 		    tv1->v_type = VAR_BOOL;
24818a7d6542SBram Moolenaar 		    tv1->vval.v_number = cmp ? VVAL_TRUE : VVAL_FALSE;
24828a7d6542SBram Moolenaar 		}
24838a7d6542SBram Moolenaar 		break;
24848a7d6542SBram Moolenaar 
24858a7d6542SBram Moolenaar 	    case ISN_COMPAREBLOB:
24868a7d6542SBram Moolenaar 		{
24878a7d6542SBram Moolenaar 		    typval_T	*tv1 = STACK_TV_BOT(-2);
24888a7d6542SBram Moolenaar 		    typval_T	*tv2 = STACK_TV_BOT(-1);
24898a7d6542SBram Moolenaar 		    blob_T	*arg1 = tv1->vval.v_blob;
24908a7d6542SBram Moolenaar 		    blob_T	*arg2 = tv2->vval.v_blob;
24918a7d6542SBram Moolenaar 		    int		cmp = FALSE;
24928a7d6542SBram Moolenaar 
24938a7d6542SBram Moolenaar 		    switch (iptr->isn_arg.op.op_type)
24948a7d6542SBram Moolenaar 		    {
24958a7d6542SBram Moolenaar 			case EXPR_EQUAL: cmp = blob_equal(arg1, arg2); break;
24968a7d6542SBram Moolenaar 			case EXPR_NEQUAL: cmp = !blob_equal(arg1, arg2); break;
24978a7d6542SBram Moolenaar 			case EXPR_IS: cmp = arg1 == arg2; break;
24988a7d6542SBram Moolenaar 			case EXPR_ISNOT: cmp = arg1 != arg2; break;
24998a7d6542SBram Moolenaar 			default: cmp = 0; break;
25008a7d6542SBram Moolenaar 		    }
25018a7d6542SBram Moolenaar 		    --ectx.ec_stack.ga_len;
25028a7d6542SBram Moolenaar 		    clear_tv(tv1);
25038a7d6542SBram Moolenaar 		    clear_tv(tv2);
25048a7d6542SBram Moolenaar 		    tv1->v_type = VAR_BOOL;
25058a7d6542SBram Moolenaar 		    tv1->vval.v_number = cmp ? VVAL_TRUE : VVAL_FALSE;
25068a7d6542SBram Moolenaar 		}
25078a7d6542SBram Moolenaar 		break;
25088a7d6542SBram Moolenaar 
25098a7d6542SBram Moolenaar 		// TODO: handle separately
25108a7d6542SBram Moolenaar 	    case ISN_COMPARESTRING:
25118a7d6542SBram Moolenaar 	    case ISN_COMPAREDICT:
25128a7d6542SBram Moolenaar 	    case ISN_COMPAREFUNC:
25138a7d6542SBram Moolenaar 	    case ISN_COMPAREANY:
25148a7d6542SBram Moolenaar 		{
25158a7d6542SBram Moolenaar 		    typval_T	*tv1 = STACK_TV_BOT(-2);
25168a7d6542SBram Moolenaar 		    typval_T	*tv2 = STACK_TV_BOT(-1);
25178a7d6542SBram Moolenaar 		    exptype_T	exptype = iptr->isn_arg.op.op_type;
25188a7d6542SBram Moolenaar 		    int		ic = iptr->isn_arg.op.op_ic;
25198a7d6542SBram Moolenaar 
2520eb26f433SBram Moolenaar 		    SOURCING_LNUM = iptr->isn_lnum;
25218a7d6542SBram Moolenaar 		    typval_compare(tv1, tv2, exptype, ic);
25228a7d6542SBram Moolenaar 		    clear_tv(tv2);
25238a7d6542SBram Moolenaar 		    --ectx.ec_stack.ga_len;
25248a7d6542SBram Moolenaar 		}
25258a7d6542SBram Moolenaar 		break;
25268a7d6542SBram Moolenaar 
25278a7d6542SBram Moolenaar 	    case ISN_ADDLIST:
25288a7d6542SBram Moolenaar 	    case ISN_ADDBLOB:
25298a7d6542SBram Moolenaar 		{
25308a7d6542SBram Moolenaar 		    typval_T *tv1 = STACK_TV_BOT(-2);
25318a7d6542SBram Moolenaar 		    typval_T *tv2 = STACK_TV_BOT(-1);
25328a7d6542SBram Moolenaar 
25331dcae599SBram Moolenaar 		    // add two lists or blobs
25348a7d6542SBram Moolenaar 		    if (iptr->isn_type == ISN_ADDLIST)
25358a7d6542SBram Moolenaar 			eval_addlist(tv1, tv2);
25368a7d6542SBram Moolenaar 		    else
25378a7d6542SBram Moolenaar 			eval_addblob(tv1, tv2);
25388a7d6542SBram Moolenaar 		    clear_tv(tv2);
25398a7d6542SBram Moolenaar 		    --ectx.ec_stack.ga_len;
25408a7d6542SBram Moolenaar 		}
25418a7d6542SBram Moolenaar 		break;
25428a7d6542SBram Moolenaar 
25431dcae599SBram Moolenaar 	    case ISN_LISTAPPEND:
25441dcae599SBram Moolenaar 		{
25451dcae599SBram Moolenaar 		    typval_T	*tv1 = STACK_TV_BOT(-2);
25461dcae599SBram Moolenaar 		    typval_T	*tv2 = STACK_TV_BOT(-1);
25471dcae599SBram Moolenaar 		    list_T	*l = tv1->vval.v_list;
25481dcae599SBram Moolenaar 
25491dcae599SBram Moolenaar 		    // add an item to a list
25501dcae599SBram Moolenaar 		    if (l == NULL)
25511dcae599SBram Moolenaar 		    {
25521dcae599SBram Moolenaar 			SOURCING_LNUM = iptr->isn_lnum;
25531dcae599SBram Moolenaar 			emsg(_(e_cannot_add_to_null_list));
25541dcae599SBram Moolenaar 			goto on_error;
25551dcae599SBram Moolenaar 		    }
25561dcae599SBram Moolenaar 		    if (list_append_tv(l, tv2) == FAIL)
25571dcae599SBram Moolenaar 			goto failed;
2558955347ccSBram Moolenaar 		    clear_tv(tv2);
25591dcae599SBram Moolenaar 		    --ectx.ec_stack.ga_len;
25601dcae599SBram Moolenaar 		}
25611dcae599SBram Moolenaar 		break;
25621dcae599SBram Moolenaar 
256380b0e5eaSBram Moolenaar 	    case ISN_BLOBAPPEND:
256480b0e5eaSBram Moolenaar 		{
256580b0e5eaSBram Moolenaar 		    typval_T	*tv1 = STACK_TV_BOT(-2);
256680b0e5eaSBram Moolenaar 		    typval_T	*tv2 = STACK_TV_BOT(-1);
256780b0e5eaSBram Moolenaar 		    blob_T	*b = tv1->vval.v_blob;
256880b0e5eaSBram Moolenaar 		    int		error = FALSE;
256980b0e5eaSBram Moolenaar 		    varnumber_T n;
257080b0e5eaSBram Moolenaar 
257180b0e5eaSBram Moolenaar 		    // add a number to a blob
257280b0e5eaSBram Moolenaar 		    if (b == NULL)
257380b0e5eaSBram Moolenaar 		    {
257480b0e5eaSBram Moolenaar 			SOURCING_LNUM = iptr->isn_lnum;
257580b0e5eaSBram Moolenaar 			emsg(_(e_cannot_add_to_null_blob));
257680b0e5eaSBram Moolenaar 			goto on_error;
257780b0e5eaSBram Moolenaar 		    }
257880b0e5eaSBram Moolenaar 		    n = tv_get_number_chk(tv2, &error);
257980b0e5eaSBram Moolenaar 		    if (error)
258080b0e5eaSBram Moolenaar 			goto on_error;
258180b0e5eaSBram Moolenaar 		    ga_append(&b->bv_ga, (int)n);
258280b0e5eaSBram Moolenaar 		    --ectx.ec_stack.ga_len;
258380b0e5eaSBram Moolenaar 		}
258480b0e5eaSBram Moolenaar 		break;
258580b0e5eaSBram Moolenaar 
25868a7d6542SBram Moolenaar 	    // Computation with two arguments of unknown type
25878a7d6542SBram Moolenaar 	    case ISN_OPANY:
25888a7d6542SBram Moolenaar 		{
25898a7d6542SBram Moolenaar 		    typval_T	*tv1 = STACK_TV_BOT(-2);
25908a7d6542SBram Moolenaar 		    typval_T	*tv2 = STACK_TV_BOT(-1);
25918a7d6542SBram Moolenaar 		    varnumber_T	n1, n2;
25928a7d6542SBram Moolenaar #ifdef FEAT_FLOAT
25938a7d6542SBram Moolenaar 		    float_T	f1 = 0, f2 = 0;
25948a7d6542SBram Moolenaar #endif
25958a7d6542SBram Moolenaar 		    int		error = FALSE;
25968a7d6542SBram Moolenaar 
25978a7d6542SBram Moolenaar 		    if (iptr->isn_arg.op.op_type == EXPR_ADD)
25988a7d6542SBram Moolenaar 		    {
25998a7d6542SBram Moolenaar 			if (tv1->v_type == VAR_LIST && tv2->v_type == VAR_LIST)
26008a7d6542SBram Moolenaar 			{
26018a7d6542SBram Moolenaar 			    eval_addlist(tv1, tv2);
26028a7d6542SBram Moolenaar 			    clear_tv(tv2);
26038a7d6542SBram Moolenaar 			    --ectx.ec_stack.ga_len;
26048a7d6542SBram Moolenaar 			    break;
26058a7d6542SBram Moolenaar 			}
26068a7d6542SBram Moolenaar 			else if (tv1->v_type == VAR_BLOB
26078a7d6542SBram Moolenaar 						    && tv2->v_type == VAR_BLOB)
26088a7d6542SBram Moolenaar 			{
26098a7d6542SBram Moolenaar 			    eval_addblob(tv1, tv2);
26108a7d6542SBram Moolenaar 			    clear_tv(tv2);
26118a7d6542SBram Moolenaar 			    --ectx.ec_stack.ga_len;
26128a7d6542SBram Moolenaar 			    break;
26138a7d6542SBram Moolenaar 			}
26148a7d6542SBram Moolenaar 		    }
26158a7d6542SBram Moolenaar #ifdef FEAT_FLOAT
26168a7d6542SBram Moolenaar 		    if (tv1->v_type == VAR_FLOAT)
26178a7d6542SBram Moolenaar 		    {
26188a7d6542SBram Moolenaar 			f1 = tv1->vval.v_float;
26198a7d6542SBram Moolenaar 			n1 = 0;
26208a7d6542SBram Moolenaar 		    }
26218a7d6542SBram Moolenaar 		    else
26228a7d6542SBram Moolenaar #endif
26238a7d6542SBram Moolenaar 		    {
2624f665e97fSBram Moolenaar 			SOURCING_LNUM = iptr->isn_lnum;
26258a7d6542SBram Moolenaar 			n1 = tv_get_number_chk(tv1, &error);
26268a7d6542SBram Moolenaar 			if (error)
2627d032f34aSBram Moolenaar 			    goto on_error;
26288a7d6542SBram Moolenaar #ifdef FEAT_FLOAT
26298a7d6542SBram Moolenaar 			if (tv2->v_type == VAR_FLOAT)
26308a7d6542SBram Moolenaar 			    f1 = n1;
26318a7d6542SBram Moolenaar #endif
26328a7d6542SBram Moolenaar 		    }
26338a7d6542SBram Moolenaar #ifdef FEAT_FLOAT
26348a7d6542SBram Moolenaar 		    if (tv2->v_type == VAR_FLOAT)
26358a7d6542SBram Moolenaar 		    {
26368a7d6542SBram Moolenaar 			f2 = tv2->vval.v_float;
26378a7d6542SBram Moolenaar 			n2 = 0;
26388a7d6542SBram Moolenaar 		    }
26398a7d6542SBram Moolenaar 		    else
26408a7d6542SBram Moolenaar #endif
26418a7d6542SBram Moolenaar 		    {
26428a7d6542SBram Moolenaar 			n2 = tv_get_number_chk(tv2, &error);
26438a7d6542SBram Moolenaar 			if (error)
2644d032f34aSBram Moolenaar 			    goto on_error;
26458a7d6542SBram Moolenaar #ifdef FEAT_FLOAT
26468a7d6542SBram Moolenaar 			if (tv1->v_type == VAR_FLOAT)
26478a7d6542SBram Moolenaar 			    f2 = n2;
26488a7d6542SBram Moolenaar #endif
26498a7d6542SBram Moolenaar 		    }
26508a7d6542SBram Moolenaar #ifdef FEAT_FLOAT
26518a7d6542SBram Moolenaar 		    // if there is a float on either side the result is a float
26528a7d6542SBram Moolenaar 		    if (tv1->v_type == VAR_FLOAT || tv2->v_type == VAR_FLOAT)
26538a7d6542SBram Moolenaar 		    {
26548a7d6542SBram Moolenaar 			switch (iptr->isn_arg.op.op_type)
26558a7d6542SBram Moolenaar 			{
26568a7d6542SBram Moolenaar 			    case EXPR_MULT: f1 = f1 * f2; break;
26578a7d6542SBram Moolenaar 			    case EXPR_DIV:  f1 = f1 / f2; break;
26588a7d6542SBram Moolenaar 			    case EXPR_SUB:  f1 = f1 - f2; break;
26598a7d6542SBram Moolenaar 			    case EXPR_ADD:  f1 = f1 + f2; break;
26607517ffdbSBram Moolenaar 			    default: SOURCING_LNUM = iptr->isn_lnum;
26617517ffdbSBram Moolenaar 				     emsg(_(e_modulus));
2662f0b9f43cSBram Moolenaar 				     goto on_error;
26638a7d6542SBram Moolenaar 			}
26648a7d6542SBram Moolenaar 			clear_tv(tv1);
26658a7d6542SBram Moolenaar 			clear_tv(tv2);
26668a7d6542SBram Moolenaar 			tv1->v_type = VAR_FLOAT;
26678a7d6542SBram Moolenaar 			tv1->vval.v_float = f1;
26688a7d6542SBram Moolenaar 			--ectx.ec_stack.ga_len;
26698a7d6542SBram Moolenaar 		    }
26708a7d6542SBram Moolenaar 		    else
26718a7d6542SBram Moolenaar #endif
26728a7d6542SBram Moolenaar 		    {
26738a7d6542SBram Moolenaar 			switch (iptr->isn_arg.op.op_type)
26748a7d6542SBram Moolenaar 			{
26758a7d6542SBram Moolenaar 			    case EXPR_MULT: n1 = n1 * n2; break;
26768a7d6542SBram Moolenaar 			    case EXPR_DIV:  n1 = num_divide(n1, n2); break;
26778a7d6542SBram Moolenaar 			    case EXPR_SUB:  n1 = n1 - n2; break;
26788a7d6542SBram Moolenaar 			    case EXPR_ADD:  n1 = n1 + n2; break;
26798a7d6542SBram Moolenaar 			    default:	    n1 = num_modulus(n1, n2); break;
26808a7d6542SBram Moolenaar 			}
26818a7d6542SBram Moolenaar 			clear_tv(tv1);
26828a7d6542SBram Moolenaar 			clear_tv(tv2);
26838a7d6542SBram Moolenaar 			tv1->v_type = VAR_NUMBER;
26848a7d6542SBram Moolenaar 			tv1->vval.v_number = n1;
26858a7d6542SBram Moolenaar 			--ectx.ec_stack.ga_len;
26868a7d6542SBram Moolenaar 		    }
26878a7d6542SBram Moolenaar 		}
26888a7d6542SBram Moolenaar 		break;
26898a7d6542SBram Moolenaar 
26908a7d6542SBram Moolenaar 	    case ISN_CONCAT:
26918a7d6542SBram Moolenaar 		{
26928a7d6542SBram Moolenaar 		    char_u *str1 = STACK_TV_BOT(-2)->vval.v_string;
26938a7d6542SBram Moolenaar 		    char_u *str2 = STACK_TV_BOT(-1)->vval.v_string;
26948a7d6542SBram Moolenaar 		    char_u *res;
26958a7d6542SBram Moolenaar 
26968a7d6542SBram Moolenaar 		    res = concat_str(str1, str2);
26978a7d6542SBram Moolenaar 		    clear_tv(STACK_TV_BOT(-2));
26988a7d6542SBram Moolenaar 		    clear_tv(STACK_TV_BOT(-1));
26998a7d6542SBram Moolenaar 		    --ectx.ec_stack.ga_len;
27008a7d6542SBram Moolenaar 		    STACK_TV_BOT(-1)->vval.v_string = res;
27018a7d6542SBram Moolenaar 		}
27028a7d6542SBram Moolenaar 		break;
27038a7d6542SBram Moolenaar 
2704bf9d8c37SBram Moolenaar 	    case ISN_STRINDEX:
270511107babSBram Moolenaar 	    case ISN_STRSLICE:
2706bf9d8c37SBram Moolenaar 		{
270711107babSBram Moolenaar 		    int		is_slice = iptr->isn_type == ISN_STRSLICE;
270811107babSBram Moolenaar 		    varnumber_T	n1 = 0, n2;
2709bf9d8c37SBram Moolenaar 		    char_u	*res;
2710bf9d8c37SBram Moolenaar 
2711bf9d8c37SBram Moolenaar 		    // string index: string is at stack-2, index at stack-1
271211107babSBram Moolenaar 		    // string slice: string is at stack-3, first index at
271311107babSBram Moolenaar 		    // stack-2, second index at stack-1
271411107babSBram Moolenaar 		    if (is_slice)
271511107babSBram Moolenaar 		    {
271611107babSBram Moolenaar 			tv = STACK_TV_BOT(-2);
271711107babSBram Moolenaar 			n1 = tv->vval.v_number;
271811107babSBram Moolenaar 		    }
271911107babSBram Moolenaar 
2720bf9d8c37SBram Moolenaar 		    tv = STACK_TV_BOT(-1);
272111107babSBram Moolenaar 		    n2 = tv->vval.v_number;
2722bf9d8c37SBram Moolenaar 
272311107babSBram Moolenaar 		    ectx.ec_stack.ga_len -= is_slice ? 2 : 1;
2724bf9d8c37SBram Moolenaar 		    tv = STACK_TV_BOT(-1);
272511107babSBram Moolenaar 		    if (is_slice)
272611107babSBram Moolenaar 			// Slice: Select the characters from the string
272711107babSBram Moolenaar 			res = string_slice(tv->vval.v_string, n1, n2);
272811107babSBram Moolenaar 		    else
272911107babSBram Moolenaar 			// Index: The resulting variable is a string of a
273011107babSBram Moolenaar 			// single character.  If the index is too big or
273111107babSBram Moolenaar 			// negative the result is empty.
273211107babSBram Moolenaar 			res = char_from_string(tv->vval.v_string, n2);
2733bf9d8c37SBram Moolenaar 		    vim_free(tv->vval.v_string);
2734bf9d8c37SBram Moolenaar 		    tv->vval.v_string = res;
2735bf9d8c37SBram Moolenaar 		}
2736bf9d8c37SBram Moolenaar 		break;
2737bf9d8c37SBram Moolenaar 
2738bf9d8c37SBram Moolenaar 	    case ISN_LISTINDEX:
2739ed591877SBram Moolenaar 	    case ISN_LISTSLICE:
27408a7d6542SBram Moolenaar 		{
2741ed591877SBram Moolenaar 		    int		is_slice = iptr->isn_type == ISN_LISTSLICE;
27428a7d6542SBram Moolenaar 		    list_T	*list;
2743ed591877SBram Moolenaar 		    varnumber_T	n1, n2;
27448a7d6542SBram Moolenaar 
27458a7d6542SBram Moolenaar 		    // list index: list is at stack-2, index at stack-1
2746ed591877SBram Moolenaar 		    // list slice: list is at stack-3, indexes at stack-2 and
2747ed591877SBram Moolenaar 		    // stack-1
2748ed591877SBram Moolenaar 		    tv = is_slice ? STACK_TV_BOT(-3) : STACK_TV_BOT(-2);
27498a7d6542SBram Moolenaar 		    list = tv->vval.v_list;
27508a7d6542SBram Moolenaar 
27518a7d6542SBram Moolenaar 		    tv = STACK_TV_BOT(-1);
2752ed591877SBram Moolenaar 		    n1 = n2 = tv->vval.v_number;
27538a7d6542SBram Moolenaar 		    clear_tv(tv);
2754ed591877SBram Moolenaar 
2755ed591877SBram Moolenaar 		    if (is_slice)
2756ed591877SBram Moolenaar 		    {
2757ed591877SBram Moolenaar 			tv = STACK_TV_BOT(-2);
2758ed591877SBram Moolenaar 			n1 = tv->vval.v_number;
2759ed591877SBram Moolenaar 			clear_tv(tv);
2760ed591877SBram Moolenaar 		    }
2761ed591877SBram Moolenaar 
2762ed591877SBram Moolenaar 		    ectx.ec_stack.ga_len -= is_slice ? 2 : 1;
2763435d8978SBram Moolenaar 		    tv = STACK_TV_BOT(-1);
27641d634542SBram Moolenaar 		    SOURCING_LNUM = iptr->isn_lnum;
2765ed591877SBram Moolenaar 		    if (list_slice_or_index(list, is_slice, n1, n2, tv, TRUE)
2766ed591877SBram Moolenaar 								       == FAIL)
2767ed591877SBram Moolenaar 			goto on_error;
27688a7d6542SBram Moolenaar 		}
27698a7d6542SBram Moolenaar 		break;
27708a7d6542SBram Moolenaar 
2771cc673e74SBram Moolenaar 	    case ISN_ANYINDEX:
2772cc673e74SBram Moolenaar 	    case ISN_ANYSLICE:
2773cc673e74SBram Moolenaar 		{
2774cc673e74SBram Moolenaar 		    int		is_slice = iptr->isn_type == ISN_ANYSLICE;
2775cc673e74SBram Moolenaar 		    typval_T	*var1, *var2;
2776cc673e74SBram Moolenaar 		    int		res;
2777cc673e74SBram Moolenaar 
2778cc673e74SBram Moolenaar 		    // index: composite is at stack-2, index at stack-1
2779cc673e74SBram Moolenaar 		    // slice: composite is at stack-3, indexes at stack-2 and
2780cc673e74SBram Moolenaar 		    // stack-1
2781cc673e74SBram Moolenaar 		    tv = is_slice ? STACK_TV_BOT(-3) : STACK_TV_BOT(-2);
27823affe7a6SBram Moolenaar 		    SOURCING_LNUM = iptr->isn_lnum;
2783cc673e74SBram Moolenaar 		    if (check_can_index(tv, TRUE, TRUE) == FAIL)
2784cc673e74SBram Moolenaar 			goto on_error;
2785cc673e74SBram Moolenaar 		    var1 = is_slice ? STACK_TV_BOT(-2) : STACK_TV_BOT(-1);
2786cc673e74SBram Moolenaar 		    var2 = is_slice ? STACK_TV_BOT(-1) : NULL;
2787cc673e74SBram Moolenaar 		    res = eval_index_inner(tv, is_slice,
2788cc673e74SBram Moolenaar 						   var1, var2, NULL, -1, TRUE);
2789cc673e74SBram Moolenaar 		    clear_tv(var1);
2790cc673e74SBram Moolenaar 		    if (is_slice)
2791cc673e74SBram Moolenaar 			clear_tv(var2);
2792cc673e74SBram Moolenaar 		    ectx.ec_stack.ga_len -= is_slice ? 2 : 1;
2793cc673e74SBram Moolenaar 		    if (res == FAIL)
2794cc673e74SBram Moolenaar 			goto on_error;
2795cc673e74SBram Moolenaar 		}
2796cc673e74SBram Moolenaar 		break;
2797cc673e74SBram Moolenaar 
27989af78769SBram Moolenaar 	    case ISN_SLICE:
27999af78769SBram Moolenaar 		{
28009af78769SBram Moolenaar 		    list_T	*list;
28019af78769SBram Moolenaar 		    int		count = iptr->isn_arg.number;
28029af78769SBram Moolenaar 
2803c5b1c20bSBram Moolenaar 		    // type will have been checked to be a list
28049af78769SBram Moolenaar 		    tv = STACK_TV_BOT(-1);
28059af78769SBram Moolenaar 		    list = tv->vval.v_list;
28069af78769SBram Moolenaar 
28079af78769SBram Moolenaar 		    // no error for short list, expect it to be checked earlier
28089af78769SBram Moolenaar 		    if (list != NULL && list->lv_len >= count)
28099af78769SBram Moolenaar 		    {
28109af78769SBram Moolenaar 			list_T	*newlist = list_slice(list,
28119af78769SBram Moolenaar 						      count, list->lv_len - 1);
28129af78769SBram Moolenaar 
28139af78769SBram Moolenaar 			if (newlist != NULL)
28149af78769SBram Moolenaar 			{
28159af78769SBram Moolenaar 			    list_unref(list);
28169af78769SBram Moolenaar 			    tv->vval.v_list = newlist;
28179af78769SBram Moolenaar 			    ++newlist->lv_refcount;
28189af78769SBram Moolenaar 			}
28199af78769SBram Moolenaar 		    }
28209af78769SBram Moolenaar 		}
28219af78769SBram Moolenaar 		break;
28229af78769SBram Moolenaar 
282347a519a9SBram Moolenaar 	    case ISN_GETITEM:
282447a519a9SBram Moolenaar 		{
282547a519a9SBram Moolenaar 		    listitem_T	*li;
282647a519a9SBram Moolenaar 		    int		index = iptr->isn_arg.number;
282747a519a9SBram Moolenaar 
2828c785b9a7SBram Moolenaar 		    // Get list item: list is at stack-1, push item.
2829c785b9a7SBram Moolenaar 		    // List type and length is checked for when compiling.
283047a519a9SBram Moolenaar 		    tv = STACK_TV_BOT(-1);
2831c785b9a7SBram Moolenaar 		    li = list_find(tv->vval.v_list, index);
283247a519a9SBram Moolenaar 
283347a519a9SBram Moolenaar 		    if (GA_GROW(&ectx.ec_stack, 1) == FAIL)
283447a519a9SBram Moolenaar 			goto failed;
283547a519a9SBram Moolenaar 		    ++ectx.ec_stack.ga_len;
283647a519a9SBram Moolenaar 		    copy_tv(&li->li_tv, STACK_TV_BOT(-1));
283747a519a9SBram Moolenaar 		}
283847a519a9SBram Moolenaar 		break;
283947a519a9SBram Moolenaar 
28408a7d6542SBram Moolenaar 	    case ISN_MEMBER:
28418a7d6542SBram Moolenaar 		{
28428a7d6542SBram Moolenaar 		    dict_T	*dict;
28431cc2a94fSBram Moolenaar 		    char_u	*key;
28441cc2a94fSBram Moolenaar 		    dictitem_T	*di;
284550788ef3SBram Moolenaar 		    typval_T	temp_tv;
28461cc2a94fSBram Moolenaar 
28471cc2a94fSBram Moolenaar 		    // dict member: dict is at stack-2, key at stack-1
28481cc2a94fSBram Moolenaar 		    tv = STACK_TV_BOT(-2);
28494dac32caSBram Moolenaar 		    // no need to check for VAR_DICT, CHECKTYPE will check.
28501cc2a94fSBram Moolenaar 		    dict = tv->vval.v_dict;
28511cc2a94fSBram Moolenaar 
28521cc2a94fSBram Moolenaar 		    tv = STACK_TV_BOT(-1);
28534dac32caSBram Moolenaar 		    // no need to check for VAR_STRING, 2STRING will check.
28541cc2a94fSBram Moolenaar 		    key = tv->vval.v_string;
2855086fc9a5SBram Moolenaar 		    if (key == NULL)
2856086fc9a5SBram Moolenaar 			key = (char_u *)"";
28574dac32caSBram Moolenaar 
28581cc2a94fSBram Moolenaar 		    if ((di = dict_find(dict, key, -1)) == NULL)
28591cc2a94fSBram Moolenaar 		    {
28607517ffdbSBram Moolenaar 			SOURCING_LNUM = iptr->isn_lnum;
28611cc2a94fSBram Moolenaar 			semsg(_(e_dictkey), key);
28624029cabbSBram Moolenaar 
28634029cabbSBram Moolenaar 			// If :silent! is used we will continue, make sure the
28644029cabbSBram Moolenaar 			// stack contents makes sense.
28654029cabbSBram Moolenaar 			clear_tv(tv);
28664029cabbSBram Moolenaar 			--ectx.ec_stack.ga_len;
28674029cabbSBram Moolenaar 			tv = STACK_TV_BOT(-1);
28684029cabbSBram Moolenaar 			clear_tv(tv);
28694029cabbSBram Moolenaar 			tv->v_type = VAR_NUMBER;
28704029cabbSBram Moolenaar 			tv->vval.v_number = 0;
2871af0df47aSBram Moolenaar 			goto on_fatal_error;
28721cc2a94fSBram Moolenaar 		    }
28731cc2a94fSBram Moolenaar 		    clear_tv(tv);
287450788ef3SBram Moolenaar 		    --ectx.ec_stack.ga_len;
2875af0df47aSBram Moolenaar 		    // Clear the dict only after getting the item, to avoid
2876af0df47aSBram Moolenaar 		    // that it makes the item invalid.
287750788ef3SBram Moolenaar 		    tv = STACK_TV_BOT(-1);
287850788ef3SBram Moolenaar 		    temp_tv = *tv;
287950788ef3SBram Moolenaar 		    copy_tv(&di->di_tv, tv);
288050788ef3SBram Moolenaar 		    clear_tv(&temp_tv);
28811cc2a94fSBram Moolenaar 		}
28821cc2a94fSBram Moolenaar 		break;
28831cc2a94fSBram Moolenaar 
28841cc2a94fSBram Moolenaar 	    // dict member with string key
28851cc2a94fSBram Moolenaar 	    case ISN_STRINGMEMBER:
28861cc2a94fSBram Moolenaar 		{
28871cc2a94fSBram Moolenaar 		    dict_T	*dict;
28888a7d6542SBram Moolenaar 		    dictitem_T	*di;
2889fb9d5c51SBram Moolenaar 		    typval_T	temp_tv;
28908a7d6542SBram Moolenaar 
28918a7d6542SBram Moolenaar 		    tv = STACK_TV_BOT(-1);
28928a7d6542SBram Moolenaar 		    if (tv->v_type != VAR_DICT || tv->vval.v_dict == NULL)
28938a7d6542SBram Moolenaar 		    {
28947517ffdbSBram Moolenaar 			SOURCING_LNUM = iptr->isn_lnum;
28958a7d6542SBram Moolenaar 			emsg(_(e_dictreq));
2896d032f34aSBram Moolenaar 			goto on_error;
28978a7d6542SBram Moolenaar 		    }
28988a7d6542SBram Moolenaar 		    dict = tv->vval.v_dict;
28998a7d6542SBram Moolenaar 
29008a7d6542SBram Moolenaar 		    if ((di = dict_find(dict, iptr->isn_arg.string, -1))
29018a7d6542SBram Moolenaar 								       == NULL)
29028a7d6542SBram Moolenaar 		    {
29037517ffdbSBram Moolenaar 			SOURCING_LNUM = iptr->isn_lnum;
29048a7d6542SBram Moolenaar 			semsg(_(e_dictkey), iptr->isn_arg.string);
2905d032f34aSBram Moolenaar 			goto on_error;
29068a7d6542SBram Moolenaar 		    }
2907fb9d5c51SBram Moolenaar 		    // Clear the dict after getting the item, to avoid that it
2908fb9d5c51SBram Moolenaar 		    // make the item invalid.
2909fb9d5c51SBram Moolenaar 		    temp_tv = *tv;
29108a7d6542SBram Moolenaar 		    copy_tv(&di->di_tv, tv);
2911fb9d5c51SBram Moolenaar 		    clear_tv(&temp_tv);
29128a7d6542SBram Moolenaar 		}
29138a7d6542SBram Moolenaar 		break;
29148a7d6542SBram Moolenaar 
29158a7d6542SBram Moolenaar 	    case ISN_NEGATENR:
29168a7d6542SBram Moolenaar 		tv = STACK_TV_BOT(-1);
2917c58164c5SBram Moolenaar 		if (tv->v_type != VAR_NUMBER
2918c58164c5SBram Moolenaar #ifdef FEAT_FLOAT
2919c58164c5SBram Moolenaar 			&& tv->v_type != VAR_FLOAT
2920c58164c5SBram Moolenaar #endif
2921c58164c5SBram Moolenaar 			)
2922c58164c5SBram Moolenaar 		{
29237517ffdbSBram Moolenaar 		    SOURCING_LNUM = iptr->isn_lnum;
2924c58164c5SBram Moolenaar 		    emsg(_(e_number_exp));
2925f0b9f43cSBram Moolenaar 		    goto on_error;
2926c58164c5SBram Moolenaar 		}
2927c58164c5SBram Moolenaar #ifdef FEAT_FLOAT
2928c58164c5SBram Moolenaar 		if (tv->v_type == VAR_FLOAT)
2929c58164c5SBram Moolenaar 		    tv->vval.v_float = -tv->vval.v_float;
2930c58164c5SBram Moolenaar 		else
2931c58164c5SBram Moolenaar #endif
29328a7d6542SBram Moolenaar 		    tv->vval.v_number = -tv->vval.v_number;
29338a7d6542SBram Moolenaar 		break;
29348a7d6542SBram Moolenaar 
29358a7d6542SBram Moolenaar 	    case ISN_CHECKNR:
29368a7d6542SBram Moolenaar 		{
29378a7d6542SBram Moolenaar 		    int		error = FALSE;
29388a7d6542SBram Moolenaar 
29398a7d6542SBram Moolenaar 		    tv = STACK_TV_BOT(-1);
29403affe7a6SBram Moolenaar 		    SOURCING_LNUM = iptr->isn_lnum;
29418a7d6542SBram Moolenaar 		    if (check_not_string(tv) == FAIL)
2942f0b9f43cSBram Moolenaar 			goto on_error;
29438a7d6542SBram Moolenaar 		    (void)tv_get_number_chk(tv, &error);
29448a7d6542SBram Moolenaar 		    if (error)
2945f0b9f43cSBram Moolenaar 			goto on_error;
29468a7d6542SBram Moolenaar 		}
29478a7d6542SBram Moolenaar 		break;
29488a7d6542SBram Moolenaar 
29498a7d6542SBram Moolenaar 	    case ISN_CHECKTYPE:
29508a7d6542SBram Moolenaar 		{
29518a7d6542SBram Moolenaar 		    checktype_T *ct = &iptr->isn_arg.type;
29528a7d6542SBram Moolenaar 
29538a7d6542SBram Moolenaar 		    tv = STACK_TV_BOT(ct->ct_off);
29545e654230SBram Moolenaar 		    SOURCING_LNUM = iptr->isn_lnum;
29555e654230SBram Moolenaar 		    if (check_typval_type(ct->ct_type, tv, 0) == FAIL)
29565e654230SBram Moolenaar 			goto on_error;
29575e654230SBram Moolenaar 
29585e654230SBram Moolenaar 		    // number 0 is FALSE, number 1 is TRUE
29595e654230SBram Moolenaar 		    if (tv->v_type == VAR_NUMBER
29605e654230SBram Moolenaar 			    && ct->ct_type->tt_type == VAR_BOOL
2961dadaddd5SBram Moolenaar 			    && (tv->vval.v_number == 0
2962dadaddd5SBram Moolenaar 						|| tv->vval.v_number == 1))
2963dadaddd5SBram Moolenaar 		    {
2964dadaddd5SBram Moolenaar 			tv->v_type = VAR_BOOL;
2965dadaddd5SBram Moolenaar 			tv->vval.v_number = tv->vval.v_number
2966dadaddd5SBram Moolenaar 						      ? VVAL_TRUE : VVAL_FALSE;
2967dadaddd5SBram Moolenaar 		    }
2968dadaddd5SBram Moolenaar 		}
29698a7d6542SBram Moolenaar 		break;
29708a7d6542SBram Moolenaar 
29719af78769SBram Moolenaar 	    case ISN_CHECKLEN:
29729af78769SBram Moolenaar 		{
29739af78769SBram Moolenaar 		    int	    min_len = iptr->isn_arg.checklen.cl_min_len;
29749af78769SBram Moolenaar 		    list_T  *list = NULL;
29759af78769SBram Moolenaar 
29769af78769SBram Moolenaar 		    tv = STACK_TV_BOT(-1);
29779af78769SBram Moolenaar 		    if (tv->v_type == VAR_LIST)
29789af78769SBram Moolenaar 			    list = tv->vval.v_list;
29799af78769SBram Moolenaar 		    if (list == NULL || list->lv_len < min_len
29809af78769SBram Moolenaar 			    || (list->lv_len > min_len
29819af78769SBram Moolenaar 					&& !iptr->isn_arg.checklen.cl_more_OK))
29829af78769SBram Moolenaar 		    {
29837517ffdbSBram Moolenaar 			SOURCING_LNUM = iptr->isn_lnum;
2984451c2e35SBram Moolenaar 			semsg(_(e_expected_nr_items_but_got_nr),
29859af78769SBram Moolenaar 				     min_len, list == NULL ? 0 : list->lv_len);
2986f0b9f43cSBram Moolenaar 			goto on_error;
29879af78769SBram Moolenaar 		    }
29889af78769SBram Moolenaar 		}
29899af78769SBram Moolenaar 		break;
29909af78769SBram Moolenaar 
29918a7d6542SBram Moolenaar 	    case ISN_2BOOL:
29922bb2658bSBram Moolenaar 	    case ISN_COND2BOOL:
29938a7d6542SBram Moolenaar 		{
29948a7d6542SBram Moolenaar 		    int n;
29952bb2658bSBram Moolenaar 		    int error = FALSE;
29968a7d6542SBram Moolenaar 
29978a7d6542SBram Moolenaar 		    tv = STACK_TV_BOT(-1);
29982bb2658bSBram Moolenaar 		    if (iptr->isn_type == ISN_2BOOL)
29992bb2658bSBram Moolenaar 		    {
30008a7d6542SBram Moolenaar 			n = tv2bool(tv);
30018a7d6542SBram Moolenaar 			if (iptr->isn_arg.number)  // invert
30028a7d6542SBram Moolenaar 			    n = !n;
30032bb2658bSBram Moolenaar 		    }
30042bb2658bSBram Moolenaar 		    else
30052bb2658bSBram Moolenaar 		    {
30062bb2658bSBram Moolenaar 			SOURCING_LNUM = iptr->isn_lnum;
30072bb2658bSBram Moolenaar 			n = tv_get_bool_chk(tv, &error);
30082bb2658bSBram Moolenaar 			if (error)
30092bb2658bSBram Moolenaar 			    goto on_error;
30102bb2658bSBram Moolenaar 		    }
30118a7d6542SBram Moolenaar 		    clear_tv(tv);
30128a7d6542SBram Moolenaar 		    tv->v_type = VAR_BOOL;
30138a7d6542SBram Moolenaar 		    tv->vval.v_number = n ? VVAL_TRUE : VVAL_FALSE;
30148a7d6542SBram Moolenaar 		}
30158a7d6542SBram Moolenaar 		break;
30168a7d6542SBram Moolenaar 
30178a7d6542SBram Moolenaar 	    case ISN_2STRING:
3018418f1df5SBram Moolenaar 	    case ISN_2STRING_ANY:
30194f5e3977SBram Moolenaar 		if (do_2string(STACK_TV_BOT(iptr->isn_arg.number),
30204f5e3977SBram Moolenaar 			iptr->isn_type == ISN_2STRING_ANY) == FAIL)
3021418f1df5SBram Moolenaar 			    goto on_error;
30228a7d6542SBram Moolenaar 		break;
30238a7d6542SBram Moolenaar 
302408597875SBram Moolenaar 	    case ISN_RANGE:
302508597875SBram Moolenaar 		{
302608597875SBram Moolenaar 		    exarg_T	ea;
302708597875SBram Moolenaar 		    char	*errormsg;
302808597875SBram Moolenaar 
302908597875SBram Moolenaar 		    if (GA_GROW(&ectx.ec_stack, 1) == FAIL)
303008597875SBram Moolenaar 			goto failed;
303108597875SBram Moolenaar 		    ++ectx.ec_stack.ga_len;
303208597875SBram Moolenaar 		    tv = STACK_TV_BOT(-1);
303308597875SBram Moolenaar 		    ea.addr_type = ADDR_LINES;
303408597875SBram Moolenaar 		    ea.cmd = iptr->isn_arg.string;
303508597875SBram Moolenaar 		    if (parse_cmd_address(&ea, &errormsg, FALSE) == FAIL)
303608597875SBram Moolenaar 			goto failed;
303708597875SBram Moolenaar 		    if (ea.addr_count == 0)
303808597875SBram Moolenaar 			tv->vval.v_number = curwin->w_cursor.lnum;
303908597875SBram Moolenaar 		    else
304008597875SBram Moolenaar 			tv->vval.v_number = ea.line2;
304108597875SBram Moolenaar 		}
304208597875SBram Moolenaar 		break;
304308597875SBram Moolenaar 
3044c3516f7eSBram Moolenaar 	    case ISN_PUT:
3045c3516f7eSBram Moolenaar 		{
3046c3516f7eSBram Moolenaar 		    int		regname = iptr->isn_arg.put.put_regname;
3047c3516f7eSBram Moolenaar 		    linenr_T	lnum = iptr->isn_arg.put.put_lnum;
3048c3516f7eSBram Moolenaar 		    char_u	*expr = NULL;
3049c3516f7eSBram Moolenaar 		    int		dir = FORWARD;
3050c3516f7eSBram Moolenaar 
3051c3516f7eSBram Moolenaar 		    if (regname == '=')
3052c3516f7eSBram Moolenaar 		    {
3053c3516f7eSBram Moolenaar 			tv = STACK_TV_BOT(-1);
3054c3516f7eSBram Moolenaar 			if (tv->v_type == VAR_STRING)
3055c3516f7eSBram Moolenaar 			    expr = tv->vval.v_string;
3056c3516f7eSBram Moolenaar 			else
3057c3516f7eSBram Moolenaar 			{
3058c3516f7eSBram Moolenaar 			    expr = typval_tostring(tv);  // allocates value
3059c3516f7eSBram Moolenaar 			    clear_tv(tv);
3060c3516f7eSBram Moolenaar 			}
3061c3516f7eSBram Moolenaar 			--ectx.ec_stack.ga_len;
3062c3516f7eSBram Moolenaar 		    }
306308597875SBram Moolenaar 		    if (lnum < -2)
306408597875SBram Moolenaar 		    {
306508597875SBram Moolenaar 			// line number was put on the stack by ISN_RANGE
306608597875SBram Moolenaar 			tv = STACK_TV_BOT(-1);
306708597875SBram Moolenaar 			curwin->w_cursor.lnum = tv->vval.v_number;
306808597875SBram Moolenaar 			if (lnum == LNUM_VARIABLE_RANGE_ABOVE)
306908597875SBram Moolenaar 			    dir = BACKWARD;
307008597875SBram Moolenaar 			--ectx.ec_stack.ga_len;
307108597875SBram Moolenaar 		    }
307208597875SBram Moolenaar 		    else if (lnum == -2)
3073c3516f7eSBram Moolenaar 			// :put! above cursor
3074c3516f7eSBram Moolenaar 			dir = BACKWARD;
3075c3516f7eSBram Moolenaar 		    else if (lnum >= 0)
3076c3516f7eSBram Moolenaar 			curwin->w_cursor.lnum = iptr->isn_arg.put.put_lnum;
3077c3516f7eSBram Moolenaar 		    check_cursor();
3078c3516f7eSBram Moolenaar 		    do_put(regname, expr, dir, 1L, PUT_LINE|PUT_CURSLINE);
3079c3516f7eSBram Moolenaar 		    vim_free(expr);
3080c3516f7eSBram Moolenaar 		}
3081c3516f7eSBram Moolenaar 		break;
3082c3516f7eSBram Moolenaar 
308302194d2bSBram Moolenaar 	    case ISN_CMDMOD:
308402194d2bSBram Moolenaar 		save_cmdmod = cmdmod;
308502194d2bSBram Moolenaar 		restore_cmdmod = TRUE;
308602194d2bSBram Moolenaar 		cmdmod = *iptr->isn_arg.cmdmod.cf_cmdmod;
308702194d2bSBram Moolenaar 		apply_cmdmod(&cmdmod);
3088f4c6e1e7SBram Moolenaar 		break;
3089f4c6e1e7SBram Moolenaar 
309002194d2bSBram Moolenaar 	    case ISN_CMDMOD_REV:
309102194d2bSBram Moolenaar 		// filter regprog is owned by the instruction, don't free it
309202194d2bSBram Moolenaar 		cmdmod.cmod_filter_regmatch.regprog = NULL;
309302194d2bSBram Moolenaar 		undo_cmdmod(&cmdmod);
309402194d2bSBram Moolenaar 		cmdmod = save_cmdmod;
309502194d2bSBram Moolenaar 		restore_cmdmod = FALSE;
3096f4c6e1e7SBram Moolenaar 		break;
3097f4c6e1e7SBram Moolenaar 
3098792f786aSBram Moolenaar 	    case ISN_UNPACK:
3099792f786aSBram Moolenaar 		{
3100792f786aSBram Moolenaar 		    int		count = iptr->isn_arg.unpack.unp_count;
3101792f786aSBram Moolenaar 		    int		semicolon = iptr->isn_arg.unpack.unp_semicolon;
3102792f786aSBram Moolenaar 		    list_T	*l;
3103792f786aSBram Moolenaar 		    listitem_T	*li;
3104792f786aSBram Moolenaar 		    int		i;
3105792f786aSBram Moolenaar 
3106792f786aSBram Moolenaar 		    // Check there is a valid list to unpack.
3107792f786aSBram Moolenaar 		    tv = STACK_TV_BOT(-1);
3108792f786aSBram Moolenaar 		    if (tv->v_type != VAR_LIST)
3109792f786aSBram Moolenaar 		    {
3110792f786aSBram Moolenaar 			SOURCING_LNUM = iptr->isn_lnum;
3111792f786aSBram Moolenaar 			emsg(_(e_for_argument_must_be_sequence_of_lists));
3112792f786aSBram Moolenaar 			goto on_error;
3113792f786aSBram Moolenaar 		    }
3114792f786aSBram Moolenaar 		    l = tv->vval.v_list;
3115792f786aSBram Moolenaar 		    if (l == NULL
3116792f786aSBram Moolenaar 				|| l->lv_len < (semicolon ? count - 1 : count))
3117792f786aSBram Moolenaar 		    {
3118792f786aSBram Moolenaar 			SOURCING_LNUM = iptr->isn_lnum;
3119792f786aSBram Moolenaar 			emsg(_(e_list_value_does_not_have_enough_items));
3120792f786aSBram Moolenaar 			goto on_error;
3121792f786aSBram Moolenaar 		    }
3122792f786aSBram Moolenaar 		    else if (!semicolon && l->lv_len > count)
3123792f786aSBram Moolenaar 		    {
3124792f786aSBram Moolenaar 			SOURCING_LNUM = iptr->isn_lnum;
3125792f786aSBram Moolenaar 			emsg(_(e_list_value_has_more_items_than_targets));
3126792f786aSBram Moolenaar 			goto on_error;
3127792f786aSBram Moolenaar 		    }
3128792f786aSBram Moolenaar 
3129792f786aSBram Moolenaar 		    CHECK_LIST_MATERIALIZE(l);
3130792f786aSBram Moolenaar 		    if (GA_GROW(&ectx.ec_stack, count - 1) == FAIL)
3131792f786aSBram Moolenaar 			goto failed;
3132792f786aSBram Moolenaar 		    ectx.ec_stack.ga_len += count - 1;
3133792f786aSBram Moolenaar 
3134792f786aSBram Moolenaar 		    // Variable after semicolon gets a list with the remaining
3135792f786aSBram Moolenaar 		    // items.
3136792f786aSBram Moolenaar 		    if (semicolon)
3137792f786aSBram Moolenaar 		    {
3138792f786aSBram Moolenaar 			list_T	*rem_list =
3139792f786aSBram Moolenaar 				  list_alloc_with_items(l->lv_len - count + 1);
3140792f786aSBram Moolenaar 
3141792f786aSBram Moolenaar 			if (rem_list == NULL)
3142792f786aSBram Moolenaar 			    goto failed;
3143792f786aSBram Moolenaar 			tv = STACK_TV_BOT(-count);
3144792f786aSBram Moolenaar 			tv->vval.v_list = rem_list;
3145792f786aSBram Moolenaar 			++rem_list->lv_refcount;
3146792f786aSBram Moolenaar 			tv->v_lock = 0;
3147792f786aSBram Moolenaar 			li = l->lv_first;
3148792f786aSBram Moolenaar 			for (i = 0; i < count - 1; ++i)
3149792f786aSBram Moolenaar 			    li = li->li_next;
3150792f786aSBram Moolenaar 			for (i = 0; li != NULL; ++i)
3151792f786aSBram Moolenaar 			{
3152792f786aSBram Moolenaar 			    list_set_item(rem_list, i, &li->li_tv);
3153792f786aSBram Moolenaar 			    li = li->li_next;
3154792f786aSBram Moolenaar 			}
3155792f786aSBram Moolenaar 			--count;
3156792f786aSBram Moolenaar 		    }
3157792f786aSBram Moolenaar 
3158792f786aSBram Moolenaar 		    // Produce the values in reverse order, first item last.
3159792f786aSBram Moolenaar 		    li = l->lv_first;
3160792f786aSBram Moolenaar 		    for (i = 0; i < count; ++i)
3161792f786aSBram Moolenaar 		    {
3162792f786aSBram Moolenaar 			tv = STACK_TV_BOT(-i - 1);
3163792f786aSBram Moolenaar 			copy_tv(&li->li_tv, tv);
3164792f786aSBram Moolenaar 			li = li->li_next;
3165792f786aSBram Moolenaar 		    }
3166792f786aSBram Moolenaar 
3167792f786aSBram Moolenaar 		    list_unref(l);
3168792f786aSBram Moolenaar 		}
3169792f786aSBram Moolenaar 		break;
3170792f786aSBram Moolenaar 
3171389df259SBram Moolenaar 	    case ISN_SHUFFLE:
3172389df259SBram Moolenaar 		{
3173389df259SBram Moolenaar 		    typval_T	tmp_tv;
3174389df259SBram Moolenaar 		    int		item = iptr->isn_arg.shuffle.shfl_item;
3175389df259SBram Moolenaar 		    int		up = iptr->isn_arg.shuffle.shfl_up;
3176389df259SBram Moolenaar 
3177389df259SBram Moolenaar 		    tmp_tv = *STACK_TV_BOT(-item);
3178389df259SBram Moolenaar 		    for ( ; up > 0 && item > 1; --up)
3179389df259SBram Moolenaar 		    {
3180389df259SBram Moolenaar 			*STACK_TV_BOT(-item) = *STACK_TV_BOT(-item + 1);
3181389df259SBram Moolenaar 			--item;
3182389df259SBram Moolenaar 		    }
3183389df259SBram Moolenaar 		    *STACK_TV_BOT(-item) = tmp_tv;
3184389df259SBram Moolenaar 		}
3185389df259SBram Moolenaar 		break;
3186389df259SBram Moolenaar 
31878a7d6542SBram Moolenaar 	    case ISN_DROP:
31888a7d6542SBram Moolenaar 		--ectx.ec_stack.ga_len;
31898a7d6542SBram Moolenaar 		clear_tv(STACK_TV_BOT(0));
31908a7d6542SBram Moolenaar 		break;
31918a7d6542SBram Moolenaar 	}
3192f0b9f43cSBram Moolenaar 	continue;
3193f0b9f43cSBram Moolenaar 
3194d032f34aSBram Moolenaar func_return:
31957cbfaa51SBram Moolenaar 	// Restore previous function. If the frame pointer is where we started
31967cbfaa51SBram Moolenaar 	// then there is none and we are done.
3197d032f34aSBram Moolenaar 	if (ectx.ec_frame_idx == initial_frame_idx)
3198d032f34aSBram Moolenaar 	    goto done;
31997cbfaa51SBram Moolenaar 
3200d032f34aSBram Moolenaar 	if (func_return(&ectx) == FAIL)
3201d032f34aSBram Moolenaar 	    // only fails when out of memory
3202d032f34aSBram Moolenaar 	    goto failed;
3203c7db5778SBram Moolenaar 	continue;
3204d032f34aSBram Moolenaar 
3205f0b9f43cSBram Moolenaar on_error:
3206af0df47aSBram Moolenaar 	// Jump here for an error that does not require aborting execution.
320756602ba1SBram Moolenaar 	// If "emsg_silent" is set then ignore the error, unless it was set
320856602ba1SBram Moolenaar 	// when calling the function.
320956602ba1SBram Moolenaar 	if (did_emsg_cumul + did_emsg == did_emsg_before
321056602ba1SBram Moolenaar 					   && emsg_silent && did_emsg_def == 0)
3211cd030c4bSBram Moolenaar 	    continue;
3212af0df47aSBram Moolenaar on_fatal_error:
3213af0df47aSBram Moolenaar 	// Jump here for an error that messes up the stack.
3214171fb923SBram Moolenaar 	// If we are not inside a try-catch started here, abort execution.
3215171fb923SBram Moolenaar 	if (trylevel <= trylevel_at_start)
3216f0b9f43cSBram Moolenaar 	    goto failed;
32178a7d6542SBram Moolenaar     }
32188a7d6542SBram Moolenaar 
32198a7d6542SBram Moolenaar done:
32208a7d6542SBram Moolenaar     // function finished, get result from the stack.
32218a7d6542SBram Moolenaar     tv = STACK_TV_BOT(-1);
32228a7d6542SBram Moolenaar     *rettv = *tv;
32238a7d6542SBram Moolenaar     tv->v_type = VAR_UNKNOWN;
32248a7d6542SBram Moolenaar     ret = OK;
32258a7d6542SBram Moolenaar 
32268a7d6542SBram Moolenaar failed:
32277eeefd4aSBram Moolenaar     // When failed need to unwind the call stack.
3228bf67ea1aSBram Moolenaar     while (ectx.ec_frame_idx != initial_frame_idx)
32297eeefd4aSBram Moolenaar 	func_return(&ectx);
3230bf67ea1aSBram Moolenaar 
3231c70bdab0SBram Moolenaar     // Deal with any remaining closures, they may be in use somewhere.
3232c70bdab0SBram Moolenaar     if (ectx.ec_funcrefs.ga_len > 0)
3233f112f30aSBram Moolenaar     {
3234c70bdab0SBram Moolenaar 	handle_closure_in_use(&ectx, FALSE);
3235f112f30aSBram Moolenaar 	ga_clear(&ectx.ec_funcrefs);  // TODO: should not be needed?
3236f112f30aSBram Moolenaar     }
3237c70bdab0SBram Moolenaar 
3238ee8580e5SBram Moolenaar     estack_pop();
3239ee8580e5SBram Moolenaar     current_sctx = save_current_sctx;
3240ee8580e5SBram Moolenaar 
3241352134bbSBram Moolenaar     if (*msg_list != NULL && saved_msg_list != NULL)
3242352134bbSBram Moolenaar     {
3243352134bbSBram Moolenaar 	msglist_T **plist = saved_msg_list;
3244352134bbSBram Moolenaar 
3245352134bbSBram Moolenaar 	// Append entries from the current msg_list (uncaught exceptions) to
3246352134bbSBram Moolenaar 	// the saved msg_list.
3247352134bbSBram Moolenaar 	while (*plist != NULL)
3248352134bbSBram Moolenaar 	    plist = &(*plist)->next;
3249352134bbSBram Moolenaar 
3250352134bbSBram Moolenaar 	*plist = *msg_list;
3251352134bbSBram Moolenaar     }
3252352134bbSBram Moolenaar     msg_list = saved_msg_list;
3253352134bbSBram Moolenaar 
325402194d2bSBram Moolenaar     if (restore_cmdmod)
325502194d2bSBram Moolenaar     {
325602194d2bSBram Moolenaar 	cmdmod.cmod_filter_regmatch.regprog = NULL;
325702194d2bSBram Moolenaar 	undo_cmdmod(&cmdmod);
325802194d2bSBram Moolenaar 	cmdmod = save_cmdmod;
325902194d2bSBram Moolenaar     }
326056602ba1SBram Moolenaar     emsg_silent_def = save_emsg_silent_def;
326156602ba1SBram Moolenaar     did_emsg_def += save_did_emsg_def;
3262f4c6e1e7SBram Moolenaar 
3263ee8580e5SBram Moolenaar failed_early:
3264bf67ea1aSBram Moolenaar     // Free all local variables, but not arguments.
32658a7d6542SBram Moolenaar     for (idx = 0; idx < ectx.ec_stack.ga_len; ++idx)
32668a7d6542SBram Moolenaar 	clear_tv(STACK_TV(idx));
3267bf67ea1aSBram Moolenaar 
32688a7d6542SBram Moolenaar     vim_free(ectx.ec_stack.ga_data);
326920431c9dSBram Moolenaar     vim_free(ectx.ec_trystack.ga_data);
3270682d0a15SBram Moolenaar 
327177e5dcc3SBram Moolenaar     // Not sure if this is necessary.
327277e5dcc3SBram Moolenaar     suppress_errthrow = save_suppress_errthrow;
327377e5dcc3SBram Moolenaar 
3274eeece9e4SBram Moolenaar     if (ret != OK && did_emsg_cumul + did_emsg == did_emsg_before)
3275451c2e35SBram Moolenaar 	semsg(_(e_unknown_error_while_executing_str),
3276682d0a15SBram Moolenaar 						   printable_func_name(ufunc));
32770ba48e8cSBram Moolenaar     funcdepth_restore(orig_funcdepth);
32788a7d6542SBram Moolenaar     return ret;
32798a7d6542SBram Moolenaar }
32808a7d6542SBram Moolenaar 
32818a7d6542SBram Moolenaar /*
32828e7d6223SBram Moolenaar  * ":disassemble".
3283777770fbSBram Moolenaar  * We don't really need this at runtime, but we do have tests that require it,
3284777770fbSBram Moolenaar  * so always include this.
32858a7d6542SBram Moolenaar  */
32868a7d6542SBram Moolenaar     void
32878a7d6542SBram Moolenaar ex_disassemble(exarg_T *eap)
32888a7d6542SBram Moolenaar {
328921456cdcSBram Moolenaar     char_u	*arg = eap->arg;
32900f18b6d1SBram Moolenaar     char_u	*fname;
32910f18b6d1SBram Moolenaar     ufunc_T	*ufunc;
32928a7d6542SBram Moolenaar     dfunc_T	*dfunc;
32938a7d6542SBram Moolenaar     isn_T	*instr;
32948a7d6542SBram Moolenaar     int		current;
32958a7d6542SBram Moolenaar     int		line_idx = 0;
32968a7d6542SBram Moolenaar     int		prev_current = 0;
32974c17ad94SBram Moolenaar     int		is_global = FALSE;
32988a7d6542SBram Moolenaar 
3299bfd65589SBram Moolenaar     if (STRNCMP(arg, "<lambda>", 8) == 0)
3300bfd65589SBram Moolenaar     {
3301bfd65589SBram Moolenaar 	arg += 8;
3302bfd65589SBram Moolenaar 	(void)getdigits(&arg);
3303bfd65589SBram Moolenaar 	fname = vim_strnsave(eap->arg, arg - eap->arg);
3304bfd65589SBram Moolenaar     }
3305bfd65589SBram Moolenaar     else
33064c17ad94SBram Moolenaar 	fname = trans_function_name(&arg, &is_global, FALSE,
3307b68b346eSBram Moolenaar 			    TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD, NULL, NULL);
330821456cdcSBram Moolenaar     if (fname == NULL)
330921456cdcSBram Moolenaar     {
331021456cdcSBram Moolenaar 	semsg(_(e_invarg2), eap->arg);
331121456cdcSBram Moolenaar 	return;
331221456cdcSBram Moolenaar     }
331321456cdcSBram Moolenaar 
33144c17ad94SBram Moolenaar     ufunc = find_func(fname, is_global, NULL);
3315a26b9700SBram Moolenaar     if (ufunc == NULL)
3316a26b9700SBram Moolenaar     {
3317a26b9700SBram Moolenaar 	char_u *p = untrans_function_name(fname);
3318a26b9700SBram Moolenaar 
3319a26b9700SBram Moolenaar 	if (p != NULL)
3320a26b9700SBram Moolenaar 	    // Try again without making it script-local.
33214c17ad94SBram Moolenaar 	    ufunc = find_func(p, FALSE, NULL);
3322a26b9700SBram Moolenaar     }
33230f18b6d1SBram Moolenaar     vim_free(fname);
33248a7d6542SBram Moolenaar     if (ufunc == NULL)
33258a7d6542SBram Moolenaar     {
3326451c2e35SBram Moolenaar 	semsg(_(e_cannot_find_function_str), eap->arg);
33278a7d6542SBram Moolenaar 	return;
33288a7d6542SBram Moolenaar     }
33290cb5bcf5SBram Moolenaar     if (ufunc->uf_def_status == UF_TO_BE_COMPILED
3330822ba247SBram Moolenaar 	    && compile_def_function(ufunc, FALSE, NULL) == FAIL)
3331822ba247SBram Moolenaar 	return;
33320cb5bcf5SBram Moolenaar     if (ufunc->uf_def_status != UF_COMPILED)
33338a7d6542SBram Moolenaar     {
3334451c2e35SBram Moolenaar 	semsg(_(e_function_is_not_compiled_str), eap->arg);
33358a7d6542SBram Moolenaar 	return;
33368a7d6542SBram Moolenaar     }
33378a7d6542SBram Moolenaar     if (ufunc->uf_name_exp != NULL)
33388a7d6542SBram Moolenaar 	msg((char *)ufunc->uf_name_exp);
33398a7d6542SBram Moolenaar     else
33408a7d6542SBram Moolenaar 	msg((char *)ufunc->uf_name);
33418a7d6542SBram Moolenaar 
33428a7d6542SBram Moolenaar     dfunc = ((dfunc_T *)def_functions.ga_data) + ufunc->uf_dfunc_idx;
33438a7d6542SBram Moolenaar     instr = dfunc->df_instr;
33448a7d6542SBram Moolenaar     for (current = 0; current < dfunc->df_instr_count; ++current)
33458a7d6542SBram Moolenaar     {
33468a7d6542SBram Moolenaar 	isn_T	    *iptr = &instr[current];
3347f2460a3aSBram Moolenaar 	char	    *line;
33488a7d6542SBram Moolenaar 
33498a7d6542SBram Moolenaar 	while (line_idx < iptr->isn_lnum && line_idx < ufunc->uf_lines.ga_len)
33508a7d6542SBram Moolenaar 	{
33518a7d6542SBram Moolenaar 	    if (current > prev_current)
33528a7d6542SBram Moolenaar 	    {
33538a7d6542SBram Moolenaar 		msg_puts("\n\n");
33548a7d6542SBram Moolenaar 		prev_current = current;
33558a7d6542SBram Moolenaar 	    }
3356f2460a3aSBram Moolenaar 	    line = ((char **)ufunc->uf_lines.ga_data)[line_idx++];
3357f2460a3aSBram Moolenaar 	    if (line != NULL)
3358f2460a3aSBram Moolenaar 		msg(line);
33598a7d6542SBram Moolenaar 	}
33608a7d6542SBram Moolenaar 
33618a7d6542SBram Moolenaar 	switch (iptr->isn_type)
33628a7d6542SBram Moolenaar 	{
33638a7d6542SBram Moolenaar 	    case ISN_EXEC:
33648a7d6542SBram Moolenaar 		smsg("%4d EXEC %s", current, iptr->isn_arg.string);
33658a7d6542SBram Moolenaar 		break;
3366cfe435d7SBram Moolenaar 	    case ISN_EXECCONCAT:
3367cfe435d7SBram Moolenaar 		smsg("%4d EXECCONCAT %lld", current,
3368cfe435d7SBram Moolenaar 					      (long long)iptr->isn_arg.number);
3369cfe435d7SBram Moolenaar 		break;
33708a7d6542SBram Moolenaar 	    case ISN_ECHO:
33718a7d6542SBram Moolenaar 		{
33728a7d6542SBram Moolenaar 		    echo_T *echo = &iptr->isn_arg.echo;
33738a7d6542SBram Moolenaar 
33748a7d6542SBram Moolenaar 		    smsg("%4d %s %d", current,
33758a7d6542SBram Moolenaar 			    echo->echo_with_white ? "ECHO" : "ECHON",
33768a7d6542SBram Moolenaar 			    echo->echo_count);
33778a7d6542SBram Moolenaar 		}
33788a7d6542SBram Moolenaar 		break;
3379ad39c094SBram Moolenaar 	    case ISN_EXECUTE:
33801082772fSBram Moolenaar 		smsg("%4d EXECUTE %lld", current,
33811082772fSBram Moolenaar 					    (long long)(iptr->isn_arg.number));
3382ad39c094SBram Moolenaar 		break;
3383f93c7feaSBram Moolenaar 	    case ISN_ECHOMSG:
3384f93c7feaSBram Moolenaar 		smsg("%4d ECHOMSG %lld", current,
3385f93c7feaSBram Moolenaar 					    (long long)(iptr->isn_arg.number));
3386f93c7feaSBram Moolenaar 		break;
3387f93c7feaSBram Moolenaar 	    case ISN_ECHOERR:
3388f93c7feaSBram Moolenaar 		smsg("%4d ECHOERR %lld", current,
3389f93c7feaSBram Moolenaar 					    (long long)(iptr->isn_arg.number));
3390f93c7feaSBram Moolenaar 		break;
33918a7d6542SBram Moolenaar 	    case ISN_LOAD:
3392c8cd2b34SBram Moolenaar 	    case ISN_LOADOUTER:
3393c8cd2b34SBram Moolenaar 		{
3394c8cd2b34SBram Moolenaar 		    char *add = iptr->isn_type == ISN_LOAD ? "" : "OUTER";
3395c8cd2b34SBram Moolenaar 
33968a7d6542SBram Moolenaar 		    if (iptr->isn_arg.number < 0)
3397c8cd2b34SBram Moolenaar 			smsg("%4d LOAD%s arg[%lld]", current, add,
3398c8cd2b34SBram Moolenaar 				(long long)(iptr->isn_arg.number
3399c8cd2b34SBram Moolenaar 							  + STACK_FRAME_SIZE));
34008a7d6542SBram Moolenaar 		    else
3401c8cd2b34SBram Moolenaar 			smsg("%4d LOAD%s $%lld", current, add,
34021082772fSBram Moolenaar 					    (long long)(iptr->isn_arg.number));
3403c8cd2b34SBram Moolenaar 		}
34048a7d6542SBram Moolenaar 		break;
34058a7d6542SBram Moolenaar 	    case ISN_LOADV:
34068a7d6542SBram Moolenaar 		smsg("%4d LOADV v:%s", current,
34078a7d6542SBram Moolenaar 				       get_vim_var_name(iptr->isn_arg.number));
34088a7d6542SBram Moolenaar 		break;
34098a7d6542SBram Moolenaar 	    case ISN_LOADSCRIPT:
34108a7d6542SBram Moolenaar 		{
34114aab88d9SBram Moolenaar 		    scriptref_T	*sref = iptr->isn_arg.script.scriptref;
34124aab88d9SBram Moolenaar 		    scriptitem_T *si = SCRIPT_ITEM(sref->sref_sid);
34138a7d6542SBram Moolenaar 		    svar_T *sv = ((svar_T *)si->sn_var_vals.ga_data)
34144aab88d9SBram Moolenaar 							      + sref->sref_idx;
34158a7d6542SBram Moolenaar 
3416fbbcd003SBram Moolenaar 		    smsg("%4d LOADSCRIPT %s-%d from %s", current,
3417fbbcd003SBram Moolenaar 					    sv->sv_name,
34184aab88d9SBram Moolenaar 					    sref->sref_idx,
3419fbbcd003SBram Moolenaar 					    si->sn_name);
34208a7d6542SBram Moolenaar 		}
34218a7d6542SBram Moolenaar 		break;
34228a7d6542SBram Moolenaar 	    case ISN_LOADS:
34238a7d6542SBram Moolenaar 		{
3424b283a8a6SBram Moolenaar 		    scriptitem_T *si = SCRIPT_ITEM(
3425b283a8a6SBram Moolenaar 					       iptr->isn_arg.loadstore.ls_sid);
34268a7d6542SBram Moolenaar 
34278a7d6542SBram Moolenaar 		    smsg("%4d LOADS s:%s from %s", current,
34285deeb3f1SBram Moolenaar 				 iptr->isn_arg.loadstore.ls_name, si->sn_name);
34298a7d6542SBram Moolenaar 		}
34308a7d6542SBram Moolenaar 		break;
343103290b84SBram Moolenaar 	    case ISN_LOADAUTO:
343203290b84SBram Moolenaar 		smsg("%4d LOADAUTO %s", current, iptr->isn_arg.string);
343303290b84SBram Moolenaar 		break;
34348a7d6542SBram Moolenaar 	    case ISN_LOADG:
34358a7d6542SBram Moolenaar 		smsg("%4d LOADG g:%s", current, iptr->isn_arg.string);
34368a7d6542SBram Moolenaar 		break;
3437d3aac291SBram Moolenaar 	    case ISN_LOADB:
3438d3aac291SBram Moolenaar 		smsg("%4d LOADB b:%s", current, iptr->isn_arg.string);
3439d3aac291SBram Moolenaar 		break;
3440d3aac291SBram Moolenaar 	    case ISN_LOADW:
3441d3aac291SBram Moolenaar 		smsg("%4d LOADW w:%s", current, iptr->isn_arg.string);
3442d3aac291SBram Moolenaar 		break;
3443d3aac291SBram Moolenaar 	    case ISN_LOADT:
3444d3aac291SBram Moolenaar 		smsg("%4d LOADT t:%s", current, iptr->isn_arg.string);
3445d3aac291SBram Moolenaar 		break;
34462f8ce0aeSBram Moolenaar 	    case ISN_LOADGDICT:
34472f8ce0aeSBram Moolenaar 		smsg("%4d LOAD g:", current);
34482f8ce0aeSBram Moolenaar 		break;
34492f8ce0aeSBram Moolenaar 	    case ISN_LOADBDICT:
34502f8ce0aeSBram Moolenaar 		smsg("%4d LOAD b:", current);
34512f8ce0aeSBram Moolenaar 		break;
34522f8ce0aeSBram Moolenaar 	    case ISN_LOADWDICT:
34532f8ce0aeSBram Moolenaar 		smsg("%4d LOAD w:", current);
34542f8ce0aeSBram Moolenaar 		break;
34552f8ce0aeSBram Moolenaar 	    case ISN_LOADTDICT:
34562f8ce0aeSBram Moolenaar 		smsg("%4d LOAD t:", current);
34572f8ce0aeSBram Moolenaar 		break;
34588a7d6542SBram Moolenaar 	    case ISN_LOADOPT:
34598a7d6542SBram Moolenaar 		smsg("%4d LOADOPT %s", current, iptr->isn_arg.string);
34608a7d6542SBram Moolenaar 		break;
34618a7d6542SBram Moolenaar 	    case ISN_LOADENV:
34628a7d6542SBram Moolenaar 		smsg("%4d LOADENV %s", current, iptr->isn_arg.string);
34638a7d6542SBram Moolenaar 		break;
34648a7d6542SBram Moolenaar 	    case ISN_LOADREG:
34651082772fSBram Moolenaar 		smsg("%4d LOADREG @%c", current, (int)(iptr->isn_arg.number));
34668a7d6542SBram Moolenaar 		break;
34678a7d6542SBram Moolenaar 
34688a7d6542SBram Moolenaar 	    case ISN_STORE:
3469b68b346eSBram Moolenaar 	    case ISN_STOREOUTER:
3470b68b346eSBram Moolenaar 		{
3471b68b346eSBram Moolenaar 		    char *add = iptr->isn_type == ISN_STORE ? "" : "OUTER";
3472b68b346eSBram Moolenaar 
3473170fcfcfSBram Moolenaar 		if (iptr->isn_arg.number < 0)
3474b68b346eSBram Moolenaar 		    smsg("%4d STORE%s arg[%lld]", current, add,
3475db99f9f2SBram Moolenaar 			 (long long)(iptr->isn_arg.number + STACK_FRAME_SIZE));
3476170fcfcfSBram Moolenaar 		else
3477b68b346eSBram Moolenaar 		    smsg("%4d STORE%s $%lld", current, add,
34781082772fSBram Moolenaar 					    (long long)(iptr->isn_arg.number));
3479b68b346eSBram Moolenaar 		}
34808a7d6542SBram Moolenaar 		break;
3481b283a8a6SBram Moolenaar 	    case ISN_STOREV:
3482b283a8a6SBram Moolenaar 		smsg("%4d STOREV v:%s", current,
3483b283a8a6SBram Moolenaar 				       get_vim_var_name(iptr->isn_arg.number));
3484b283a8a6SBram Moolenaar 		break;
348503290b84SBram Moolenaar 	    case ISN_STOREAUTO:
348603290b84SBram Moolenaar 		smsg("%4d STOREAUTO %s", current, iptr->isn_arg.string);
348703290b84SBram Moolenaar 		break;
34888a7d6542SBram Moolenaar 	    case ISN_STOREG:
3489b283a8a6SBram Moolenaar 		smsg("%4d STOREG %s", current, iptr->isn_arg.string);
3490b283a8a6SBram Moolenaar 		break;
3491d3aac291SBram Moolenaar 	    case ISN_STOREB:
3492d3aac291SBram Moolenaar 		smsg("%4d STOREB %s", current, iptr->isn_arg.string);
3493d3aac291SBram Moolenaar 		break;
3494d3aac291SBram Moolenaar 	    case ISN_STOREW:
3495d3aac291SBram Moolenaar 		smsg("%4d STOREW %s", current, iptr->isn_arg.string);
3496d3aac291SBram Moolenaar 		break;
3497d3aac291SBram Moolenaar 	    case ISN_STORET:
3498d3aac291SBram Moolenaar 		smsg("%4d STORET %s", current, iptr->isn_arg.string);
3499d3aac291SBram Moolenaar 		break;
3500b283a8a6SBram Moolenaar 	    case ISN_STORES:
3501b283a8a6SBram Moolenaar 		{
3502b283a8a6SBram Moolenaar 		    scriptitem_T *si = SCRIPT_ITEM(
3503b283a8a6SBram Moolenaar 					       iptr->isn_arg.loadstore.ls_sid);
3504b283a8a6SBram Moolenaar 
35050bbf722aSBram Moolenaar 		    smsg("%4d STORES %s in %s", current,
35065deeb3f1SBram Moolenaar 				 iptr->isn_arg.loadstore.ls_name, si->sn_name);
3507b283a8a6SBram Moolenaar 		}
35088a7d6542SBram Moolenaar 		break;
35098a7d6542SBram Moolenaar 	    case ISN_STORESCRIPT:
35108a7d6542SBram Moolenaar 		{
35114aab88d9SBram Moolenaar 		    scriptref_T	*sref = iptr->isn_arg.script.scriptref;
35124aab88d9SBram Moolenaar 		    scriptitem_T *si = SCRIPT_ITEM(sref->sref_sid);
35138a7d6542SBram Moolenaar 		    svar_T *sv = ((svar_T *)si->sn_var_vals.ga_data)
35144aab88d9SBram Moolenaar 							      + sref->sref_idx;
35158a7d6542SBram Moolenaar 
3516fbbcd003SBram Moolenaar 		    smsg("%4d STORESCRIPT %s-%d in %s", current,
3517fbbcd003SBram Moolenaar 					     sv->sv_name,
35184aab88d9SBram Moolenaar 					     sref->sref_idx,
3519fbbcd003SBram Moolenaar 					     si->sn_name);
35208a7d6542SBram Moolenaar 		}
35218a7d6542SBram Moolenaar 		break;
35228a7d6542SBram Moolenaar 	    case ISN_STOREOPT:
35238a7d6542SBram Moolenaar 		smsg("%4d STOREOPT &%s", current,
35248a7d6542SBram Moolenaar 					       iptr->isn_arg.storeopt.so_name);
35258a7d6542SBram Moolenaar 		break;
3526b283a8a6SBram Moolenaar 	    case ISN_STOREENV:
3527b283a8a6SBram Moolenaar 		smsg("%4d STOREENV $%s", current, iptr->isn_arg.string);
3528b283a8a6SBram Moolenaar 		break;
3529b283a8a6SBram Moolenaar 	    case ISN_STOREREG:
35301082772fSBram Moolenaar 		smsg("%4d STOREREG @%c", current, (int)iptr->isn_arg.number);
3531b283a8a6SBram Moolenaar 		break;
35328a7d6542SBram Moolenaar 	    case ISN_STORENR:
35338a7d6542SBram Moolenaar 		smsg("%4d STORE %lld in $%d", current,
3534a471eeaeSBram Moolenaar 				iptr->isn_arg.storenr.stnr_val,
3535a471eeaeSBram Moolenaar 				iptr->isn_arg.storenr.stnr_idx);
35368a7d6542SBram Moolenaar 		break;
35378a7d6542SBram Moolenaar 
35384f5e3977SBram Moolenaar 	    case ISN_STOREINDEX:
35394f5e3977SBram Moolenaar 		switch (iptr->isn_arg.vartype)
35404f5e3977SBram Moolenaar 		{
35414f5e3977SBram Moolenaar 		    case VAR_LIST:
35421cc2a94fSBram Moolenaar 			    smsg("%4d STORELIST", current);
35431cc2a94fSBram Moolenaar 			    break;
35444f5e3977SBram Moolenaar 		    case VAR_DICT:
35451cc2a94fSBram Moolenaar 			    smsg("%4d STOREDICT", current);
35461cc2a94fSBram Moolenaar 			    break;
35474f5e3977SBram Moolenaar 		    case VAR_ANY:
35484f5e3977SBram Moolenaar 			    smsg("%4d STOREINDEX", current);
35494f5e3977SBram Moolenaar 			    break;
35504f5e3977SBram Moolenaar 		    default: break;
35514f5e3977SBram Moolenaar 		}
35524f5e3977SBram Moolenaar 		break;
35531cc2a94fSBram Moolenaar 
35548a7d6542SBram Moolenaar 	    // constants
35558a7d6542SBram Moolenaar 	    case ISN_PUSHNR:
35561082772fSBram Moolenaar 		smsg("%4d PUSHNR %lld", current,
35571082772fSBram Moolenaar 					    (long long)(iptr->isn_arg.number));
35588a7d6542SBram Moolenaar 		break;
35598a7d6542SBram Moolenaar 	    case ISN_PUSHBOOL:
35608a7d6542SBram Moolenaar 	    case ISN_PUSHSPEC:
35618a7d6542SBram Moolenaar 		smsg("%4d PUSH %s", current,
35628a7d6542SBram Moolenaar 				   get_var_special_name(iptr->isn_arg.number));
35638a7d6542SBram Moolenaar 		break;
35648a7d6542SBram Moolenaar 	    case ISN_PUSHF:
3565a5d5953dSBram Moolenaar #ifdef FEAT_FLOAT
35668a7d6542SBram Moolenaar 		smsg("%4d PUSHF %g", current, iptr->isn_arg.fnumber);
3567a5d5953dSBram Moolenaar #endif
35688a7d6542SBram Moolenaar 		break;
35698a7d6542SBram Moolenaar 	    case ISN_PUSHS:
35708a7d6542SBram Moolenaar 		smsg("%4d PUSHS \"%s\"", current, iptr->isn_arg.string);
35718a7d6542SBram Moolenaar 		break;
35728a7d6542SBram Moolenaar 	    case ISN_PUSHBLOB:
35738a7d6542SBram Moolenaar 		{
35748a7d6542SBram Moolenaar 		    char_u	*r;
35758a7d6542SBram Moolenaar 		    char_u	numbuf[NUMBUFLEN];
35768a7d6542SBram Moolenaar 		    char_u	*tofree;
35778a7d6542SBram Moolenaar 
35788a7d6542SBram Moolenaar 		    r = blob2string(iptr->isn_arg.blob, &tofree, numbuf);
3579ff80cb68SBram Moolenaar 		    smsg("%4d PUSHBLOB %s", current, r);
35808a7d6542SBram Moolenaar 		    vim_free(tofree);
35818a7d6542SBram Moolenaar 		}
35828a7d6542SBram Moolenaar 		break;
358342a480bfSBram Moolenaar 	    case ISN_PUSHFUNC:
3584087d2e15SBram Moolenaar 		{
3585087d2e15SBram Moolenaar 		    char *name = (char *)iptr->isn_arg.string;
3586087d2e15SBram Moolenaar 
3587087d2e15SBram Moolenaar 		    smsg("%4d PUSHFUNC \"%s\"", current,
3588087d2e15SBram Moolenaar 					       name == NULL ? "[none]" : name);
3589087d2e15SBram Moolenaar 		}
359042a480bfSBram Moolenaar 		break;
359142a480bfSBram Moolenaar 	    case ISN_PUSHCHANNEL:
359242a480bfSBram Moolenaar #ifdef FEAT_JOB_CHANNEL
359342a480bfSBram Moolenaar 		{
359442a480bfSBram Moolenaar 		    channel_T *channel = iptr->isn_arg.channel;
359542a480bfSBram Moolenaar 
359642a480bfSBram Moolenaar 		    smsg("%4d PUSHCHANNEL %d", current,
359742a480bfSBram Moolenaar 					 channel == NULL ? 0 : channel->ch_id);
359842a480bfSBram Moolenaar 		}
359942a480bfSBram Moolenaar #endif
360042a480bfSBram Moolenaar 		break;
360142a480bfSBram Moolenaar 	    case ISN_PUSHJOB:
360242a480bfSBram Moolenaar #ifdef FEAT_JOB_CHANNEL
360342a480bfSBram Moolenaar 		{
360442a480bfSBram Moolenaar 		    typval_T	tv;
360542a480bfSBram Moolenaar 		    char_u	*name;
360642a480bfSBram Moolenaar 
360742a480bfSBram Moolenaar 		    tv.v_type = VAR_JOB;
360842a480bfSBram Moolenaar 		    tv.vval.v_job = iptr->isn_arg.job;
360942a480bfSBram Moolenaar 		    name = tv_get_string(&tv);
3610f51cb4e0SBram Moolenaar 		    smsg("%4d PUSHJOB \"%s\"", current, name);
361142a480bfSBram Moolenaar 		}
361242a480bfSBram Moolenaar #endif
361342a480bfSBram Moolenaar 		break;
36148a7d6542SBram Moolenaar 	    case ISN_PUSHEXC:
36158a7d6542SBram Moolenaar 		smsg("%4d PUSH v:exception", current);
36168a7d6542SBram Moolenaar 		break;
3617d72c1bf0SBram Moolenaar 	    case ISN_UNLET:
3618d72c1bf0SBram Moolenaar 		smsg("%4d UNLET%s %s", current,
3619d72c1bf0SBram Moolenaar 			iptr->isn_arg.unlet.ul_forceit ? "!" : "",
3620d72c1bf0SBram Moolenaar 			iptr->isn_arg.unlet.ul_name);
3621d72c1bf0SBram Moolenaar 		break;
36227bdaea6eSBram Moolenaar 	    case ISN_UNLETENV:
36237bdaea6eSBram Moolenaar 		smsg("%4d UNLETENV%s $%s", current,
36247bdaea6eSBram Moolenaar 			iptr->isn_arg.unlet.ul_forceit ? "!" : "",
36257bdaea6eSBram Moolenaar 			iptr->isn_arg.unlet.ul_name);
36267bdaea6eSBram Moolenaar 		break;
36270b4c66c6SBram Moolenaar 	    case ISN_LOCKCONST:
36280b4c66c6SBram Moolenaar 		smsg("%4d LOCKCONST", current);
36290b4c66c6SBram Moolenaar 		break;
36308a7d6542SBram Moolenaar 	    case ISN_NEWLIST:
36311082772fSBram Moolenaar 		smsg("%4d NEWLIST size %lld", current,
36321082772fSBram Moolenaar 					    (long long)(iptr->isn_arg.number));
36338a7d6542SBram Moolenaar 		break;
36348a7d6542SBram Moolenaar 	    case ISN_NEWDICT:
36351082772fSBram Moolenaar 		smsg("%4d NEWDICT size %lld", current,
36361082772fSBram Moolenaar 					    (long long)(iptr->isn_arg.number));
36378a7d6542SBram Moolenaar 		break;
36388a7d6542SBram Moolenaar 
36398a7d6542SBram Moolenaar 	    // function call
36408a7d6542SBram Moolenaar 	    case ISN_BCALL:
36418a7d6542SBram Moolenaar 		{
36428a7d6542SBram Moolenaar 		    cbfunc_T	*cbfunc = &iptr->isn_arg.bfunc;
36438a7d6542SBram Moolenaar 
36448a7d6542SBram Moolenaar 		    smsg("%4d BCALL %s(argc %d)", current,
36458a7d6542SBram Moolenaar 			    internal_func_name(cbfunc->cbf_idx),
36468a7d6542SBram Moolenaar 			    cbfunc->cbf_argcount);
36478a7d6542SBram Moolenaar 		}
36488a7d6542SBram Moolenaar 		break;
36498a7d6542SBram Moolenaar 	    case ISN_DCALL:
36508a7d6542SBram Moolenaar 		{
36518a7d6542SBram Moolenaar 		    cdfunc_T	*cdfunc = &iptr->isn_arg.dfunc;
36528a7d6542SBram Moolenaar 		    dfunc_T	*df = ((dfunc_T *)def_functions.ga_data)
36538a7d6542SBram Moolenaar 							     + cdfunc->cdf_idx;
36548a7d6542SBram Moolenaar 
36558a7d6542SBram Moolenaar 		    smsg("%4d DCALL %s(argc %d)", current,
36568a7d6542SBram Moolenaar 			    df->df_ufunc->uf_name_exp != NULL
36578a7d6542SBram Moolenaar 				? df->df_ufunc->uf_name_exp
36588a7d6542SBram Moolenaar 				: df->df_ufunc->uf_name, cdfunc->cdf_argcount);
36598a7d6542SBram Moolenaar 		}
36608a7d6542SBram Moolenaar 		break;
36618a7d6542SBram Moolenaar 	    case ISN_UCALL:
36628a7d6542SBram Moolenaar 		{
36638a7d6542SBram Moolenaar 		    cufunc_T	*cufunc = &iptr->isn_arg.ufunc;
36648a7d6542SBram Moolenaar 
36658a7d6542SBram Moolenaar 		    smsg("%4d UCALL %s(argc %d)", current,
36668a7d6542SBram Moolenaar 				       cufunc->cuf_name, cufunc->cuf_argcount);
36678a7d6542SBram Moolenaar 		}
36688a7d6542SBram Moolenaar 		break;
36698a7d6542SBram Moolenaar 	    case ISN_PCALL:
36708a7d6542SBram Moolenaar 		{
36718a7d6542SBram Moolenaar 		    cpfunc_T	*cpfunc = &iptr->isn_arg.pfunc;
36728a7d6542SBram Moolenaar 
36738a7d6542SBram Moolenaar 		    smsg("%4d PCALL%s (argc %d)", current,
36748a7d6542SBram Moolenaar 			   cpfunc->cpf_top ? " top" : "", cpfunc->cpf_argcount);
36758a7d6542SBram Moolenaar 		}
36768a7d6542SBram Moolenaar 		break;
3677bd5da371SBram Moolenaar 	    case ISN_PCALL_END:
3678bd5da371SBram Moolenaar 		smsg("%4d PCALL end", current);
3679bd5da371SBram Moolenaar 		break;
36808a7d6542SBram Moolenaar 	    case ISN_RETURN:
36818a7d6542SBram Moolenaar 		smsg("%4d RETURN", current);
36828a7d6542SBram Moolenaar 		break;
36838a7d6542SBram Moolenaar 	    case ISN_FUNCREF:
36848a7d6542SBram Moolenaar 		{
36855adc55cbSBram Moolenaar 		    funcref_T	*funcref = &iptr->isn_arg.funcref;
36868a7d6542SBram Moolenaar 		    dfunc_T	*df = ((dfunc_T *)def_functions.ga_data)
36875adc55cbSBram Moolenaar 							    + funcref->fr_func;
36888a7d6542SBram Moolenaar 
3689148ce7aeSBram Moolenaar 		    smsg("%4d FUNCREF %s", current, df->df_ufunc->uf_name);
36908a7d6542SBram Moolenaar 		}
36918a7d6542SBram Moolenaar 		break;
36928a7d6542SBram Moolenaar 
369338ddf333SBram Moolenaar 	    case ISN_NEWFUNC:
369438ddf333SBram Moolenaar 		{
369538ddf333SBram Moolenaar 		    newfunc_T	*newfunc = &iptr->isn_arg.newfunc;
369638ddf333SBram Moolenaar 
369738ddf333SBram Moolenaar 		    smsg("%4d NEWFUNC %s %s", current,
369838ddf333SBram Moolenaar 				       newfunc->nf_lambda, newfunc->nf_global);
369938ddf333SBram Moolenaar 		}
370038ddf333SBram Moolenaar 		break;
370138ddf333SBram Moolenaar 
37026abdcf82SBram Moolenaar 	    case ISN_DEF:
37036abdcf82SBram Moolenaar 		{
37046abdcf82SBram Moolenaar 		    char_u *name = iptr->isn_arg.string;
37056abdcf82SBram Moolenaar 
37066abdcf82SBram Moolenaar 		    smsg("%4d DEF %s", current,
37076abdcf82SBram Moolenaar 					   name == NULL ? (char_u *)"" : name);
37086abdcf82SBram Moolenaar 		}
37096abdcf82SBram Moolenaar 		break;
37106abdcf82SBram Moolenaar 
37118a7d6542SBram Moolenaar 	    case ISN_JUMP:
37128a7d6542SBram Moolenaar 		{
37138a7d6542SBram Moolenaar 		    char *when = "?";
37148a7d6542SBram Moolenaar 
37158a7d6542SBram Moolenaar 		    switch (iptr->isn_arg.jump.jump_when)
37168a7d6542SBram Moolenaar 		    {
37178a7d6542SBram Moolenaar 			case JUMP_ALWAYS:
37188a7d6542SBram Moolenaar 			    when = "JUMP";
37198a7d6542SBram Moolenaar 			    break;
37208a7d6542SBram Moolenaar 			case JUMP_AND_KEEP_IF_TRUE:
37218a7d6542SBram Moolenaar 			    when = "JUMP_AND_KEEP_IF_TRUE";
37228a7d6542SBram Moolenaar 			    break;
37238a7d6542SBram Moolenaar 			case JUMP_IF_FALSE:
37248a7d6542SBram Moolenaar 			    when = "JUMP_IF_FALSE";
37258a7d6542SBram Moolenaar 			    break;
37268a7d6542SBram Moolenaar 			case JUMP_AND_KEEP_IF_FALSE:
37278a7d6542SBram Moolenaar 			    when = "JUMP_AND_KEEP_IF_FALSE";
37288a7d6542SBram Moolenaar 			    break;
37292bb2658bSBram Moolenaar 			case JUMP_IF_COND_FALSE:
37302bb2658bSBram Moolenaar 			    when = "JUMP_IF_COND_FALSE";
37312bb2658bSBram Moolenaar 			    break;
37322bb2658bSBram Moolenaar 			case JUMP_IF_COND_TRUE:
37332bb2658bSBram Moolenaar 			    when = "JUMP_IF_COND_TRUE";
37342bb2658bSBram Moolenaar 			    break;
37358a7d6542SBram Moolenaar 		    }
37368a677a37SBram Moolenaar 		    smsg("%4d %s -> %d", current, when,
37378a7d6542SBram Moolenaar 						iptr->isn_arg.jump.jump_where);
37388a7d6542SBram Moolenaar 		}
37398a7d6542SBram Moolenaar 		break;
37408a7d6542SBram Moolenaar 
37418a7d6542SBram Moolenaar 	    case ISN_FOR:
37428a7d6542SBram Moolenaar 		{
37438a7d6542SBram Moolenaar 		    forloop_T *forloop = &iptr->isn_arg.forloop;
37448a7d6542SBram Moolenaar 
37458a7d6542SBram Moolenaar 		    smsg("%4d FOR $%d -> %d", current,
37468a7d6542SBram Moolenaar 					   forloop->for_idx, forloop->for_end);
37478a7d6542SBram Moolenaar 		}
37488a7d6542SBram Moolenaar 		break;
37498a7d6542SBram Moolenaar 
37508a7d6542SBram Moolenaar 	    case ISN_TRY:
37518a7d6542SBram Moolenaar 		{
37528a7d6542SBram Moolenaar 		    try_T *try = &iptr->isn_arg.try;
37538a7d6542SBram Moolenaar 
37548a7d6542SBram Moolenaar 		    smsg("%4d TRY catch -> %d, finally -> %d", current,
37558a7d6542SBram Moolenaar 					     try->try_catch, try->try_finally);
37568a7d6542SBram Moolenaar 		}
37578a7d6542SBram Moolenaar 		break;
37588a7d6542SBram Moolenaar 	    case ISN_CATCH:
37598a7d6542SBram Moolenaar 		// TODO
37608a7d6542SBram Moolenaar 		smsg("%4d CATCH", current);
37618a7d6542SBram Moolenaar 		break;
37628a7d6542SBram Moolenaar 	    case ISN_ENDTRY:
37638a7d6542SBram Moolenaar 		smsg("%4d ENDTRY", current);
37648a7d6542SBram Moolenaar 		break;
37658a7d6542SBram Moolenaar 	    case ISN_THROW:
37668a7d6542SBram Moolenaar 		smsg("%4d THROW", current);
37678a7d6542SBram Moolenaar 		break;
37688a7d6542SBram Moolenaar 
37698a7d6542SBram Moolenaar 	    // expression operations on number
37708a7d6542SBram Moolenaar 	    case ISN_OPNR:
37718a7d6542SBram Moolenaar 	    case ISN_OPFLOAT:
37728a7d6542SBram Moolenaar 	    case ISN_OPANY:
37738a7d6542SBram Moolenaar 		{
37748a7d6542SBram Moolenaar 		    char *what;
37758a7d6542SBram Moolenaar 		    char *ins;
37768a7d6542SBram Moolenaar 
37778a7d6542SBram Moolenaar 		    switch (iptr->isn_arg.op.op_type)
37788a7d6542SBram Moolenaar 		    {
37798a7d6542SBram Moolenaar 			case EXPR_MULT: what = "*"; break;
37808a7d6542SBram Moolenaar 			case EXPR_DIV: what = "/"; break;
37818a7d6542SBram Moolenaar 			case EXPR_REM: what = "%"; break;
37828a7d6542SBram Moolenaar 			case EXPR_SUB: what = "-"; break;
37838a7d6542SBram Moolenaar 			case EXPR_ADD: what = "+"; break;
37848a7d6542SBram Moolenaar 			default:       what = "???"; break;
37858a7d6542SBram Moolenaar 		    }
37868a7d6542SBram Moolenaar 		    switch (iptr->isn_type)
37878a7d6542SBram Moolenaar 		    {
37888a7d6542SBram Moolenaar 			case ISN_OPNR: ins = "OPNR"; break;
37898a7d6542SBram Moolenaar 			case ISN_OPFLOAT: ins = "OPFLOAT"; break;
37908a7d6542SBram Moolenaar 			case ISN_OPANY: ins = "OPANY"; break;
37918a7d6542SBram Moolenaar 			default: ins = "???"; break;
37928a7d6542SBram Moolenaar 		    }
37938a7d6542SBram Moolenaar 		    smsg("%4d %s %s", current, ins, what);
37948a7d6542SBram Moolenaar 		}
37958a7d6542SBram Moolenaar 		break;
37968a7d6542SBram Moolenaar 
37978a7d6542SBram Moolenaar 	    case ISN_COMPAREBOOL:
37988a7d6542SBram Moolenaar 	    case ISN_COMPARESPECIAL:
37998a7d6542SBram Moolenaar 	    case ISN_COMPARENR:
38008a7d6542SBram Moolenaar 	    case ISN_COMPAREFLOAT:
38018a7d6542SBram Moolenaar 	    case ISN_COMPARESTRING:
38028a7d6542SBram Moolenaar 	    case ISN_COMPAREBLOB:
38038a7d6542SBram Moolenaar 	    case ISN_COMPARELIST:
38048a7d6542SBram Moolenaar 	    case ISN_COMPAREDICT:
38058a7d6542SBram Moolenaar 	    case ISN_COMPAREFUNC:
38068a7d6542SBram Moolenaar 	    case ISN_COMPAREANY:
38078a7d6542SBram Moolenaar 		   {
38088a7d6542SBram Moolenaar 		       char *p;
38098a7d6542SBram Moolenaar 		       char buf[10];
38108a7d6542SBram Moolenaar 		       char *type;
38118a7d6542SBram Moolenaar 
38128a7d6542SBram Moolenaar 		       switch (iptr->isn_arg.op.op_type)
38138a7d6542SBram Moolenaar 		       {
38148a7d6542SBram Moolenaar 			   case EXPR_EQUAL:	 p = "=="; break;
38158a7d6542SBram Moolenaar 			   case EXPR_NEQUAL:    p = "!="; break;
38168a7d6542SBram Moolenaar 			   case EXPR_GREATER:   p = ">"; break;
38178a7d6542SBram Moolenaar 			   case EXPR_GEQUAL:    p = ">="; break;
38188a7d6542SBram Moolenaar 			   case EXPR_SMALLER:   p = "<"; break;
38198a7d6542SBram Moolenaar 			   case EXPR_SEQUAL:    p = "<="; break;
38208a7d6542SBram Moolenaar 			   case EXPR_MATCH:	 p = "=~"; break;
38218a7d6542SBram Moolenaar 			   case EXPR_IS:	 p = "is"; break;
38228a7d6542SBram Moolenaar 			   case EXPR_ISNOT:	 p = "isnot"; break;
38238a7d6542SBram Moolenaar 			   case EXPR_NOMATCH:	 p = "!~"; break;
38248a7d6542SBram Moolenaar 			   default:  p = "???"; break;
38258a7d6542SBram Moolenaar 		       }
38268a7d6542SBram Moolenaar 		       STRCPY(buf, p);
38278a7d6542SBram Moolenaar 		       if (iptr->isn_arg.op.op_ic == TRUE)
38288a7d6542SBram Moolenaar 			   strcat(buf, "?");
38298a7d6542SBram Moolenaar 		       switch(iptr->isn_type)
38308a7d6542SBram Moolenaar 		       {
38318a7d6542SBram Moolenaar 			   case ISN_COMPAREBOOL: type = "COMPAREBOOL"; break;
38328a7d6542SBram Moolenaar 			   case ISN_COMPARESPECIAL:
38338a7d6542SBram Moolenaar 						 type = "COMPARESPECIAL"; break;
38348a7d6542SBram Moolenaar 			   case ISN_COMPARENR: type = "COMPARENR"; break;
38358a7d6542SBram Moolenaar 			   case ISN_COMPAREFLOAT: type = "COMPAREFLOAT"; break;
38368a7d6542SBram Moolenaar 			   case ISN_COMPARESTRING:
38378a7d6542SBram Moolenaar 						  type = "COMPARESTRING"; break;
38388a7d6542SBram Moolenaar 			   case ISN_COMPAREBLOB: type = "COMPAREBLOB"; break;
38398a7d6542SBram Moolenaar 			   case ISN_COMPARELIST: type = "COMPARELIST"; break;
38408a7d6542SBram Moolenaar 			   case ISN_COMPAREDICT: type = "COMPAREDICT"; break;
38418a7d6542SBram Moolenaar 			   case ISN_COMPAREFUNC: type = "COMPAREFUNC"; break;
38428a7d6542SBram Moolenaar 			   case ISN_COMPAREANY: type = "COMPAREANY"; break;
38438a7d6542SBram Moolenaar 			   default: type = "???"; break;
38448a7d6542SBram Moolenaar 		       }
38458a7d6542SBram Moolenaar 
38468a7d6542SBram Moolenaar 		       smsg("%4d %s %s", current, type, buf);
38478a7d6542SBram Moolenaar 		   }
38488a7d6542SBram Moolenaar 		   break;
38498a7d6542SBram Moolenaar 
38508a7d6542SBram Moolenaar 	    case ISN_ADDLIST: smsg("%4d ADDLIST", current); break;
38518a7d6542SBram Moolenaar 	    case ISN_ADDBLOB: smsg("%4d ADDBLOB", current); break;
38528a7d6542SBram Moolenaar 
38538a7d6542SBram Moolenaar 	    // expression operations
38548a7d6542SBram Moolenaar 	    case ISN_CONCAT: smsg("%4d CONCAT", current); break;
3855bf9d8c37SBram Moolenaar 	    case ISN_STRINDEX: smsg("%4d STRINDEX", current); break;
385611107babSBram Moolenaar 	    case ISN_STRSLICE: smsg("%4d STRSLICE", current); break;
38571dcae599SBram Moolenaar 	    case ISN_LISTAPPEND: smsg("%4d LISTAPPEND", current); break;
385880b0e5eaSBram Moolenaar 	    case ISN_BLOBAPPEND: smsg("%4d BLOBAPPEND", current); break;
3859bf9d8c37SBram Moolenaar 	    case ISN_LISTINDEX: smsg("%4d LISTINDEX", current); break;
3860ed591877SBram Moolenaar 	    case ISN_LISTSLICE: smsg("%4d LISTSLICE", current); break;
3861cc673e74SBram Moolenaar 	    case ISN_ANYINDEX: smsg("%4d ANYINDEX", current); break;
3862cc673e74SBram Moolenaar 	    case ISN_ANYSLICE: smsg("%4d ANYSLICE", current); break;
38639af78769SBram Moolenaar 	    case ISN_SLICE: smsg("%4d SLICE %lld",
38649af78769SBram Moolenaar 					 current, iptr->isn_arg.number); break;
386547a519a9SBram Moolenaar 	    case ISN_GETITEM: smsg("%4d ITEM %lld",
386647a519a9SBram Moolenaar 					 current, iptr->isn_arg.number); break;
38671cc2a94fSBram Moolenaar 	    case ISN_MEMBER: smsg("%4d MEMBER", current); break;
38681cc2a94fSBram Moolenaar 	    case ISN_STRINGMEMBER: smsg("%4d MEMBER %s", current,
38698a7d6542SBram Moolenaar 						  iptr->isn_arg.string); break;
38708a7d6542SBram Moolenaar 	    case ISN_NEGATENR: smsg("%4d NEGATENR", current); break;
38718a7d6542SBram Moolenaar 
38728a7d6542SBram Moolenaar 	    case ISN_CHECKNR: smsg("%4d CHECKNR", current); break;
38735e654230SBram Moolenaar 	    case ISN_CHECKTYPE:
38745e654230SBram Moolenaar 		  {
38755e654230SBram Moolenaar 		      char *tofree;
38765e654230SBram Moolenaar 
38775e654230SBram Moolenaar 		      smsg("%4d CHECKTYPE %s stack[%d]", current,
38785e654230SBram Moolenaar 			      type_name(iptr->isn_arg.type.ct_type, &tofree),
38798a7d6542SBram Moolenaar 			      iptr->isn_arg.type.ct_off);
38805e654230SBram Moolenaar 		      vim_free(tofree);
38818a7d6542SBram Moolenaar 		      break;
38825e654230SBram Moolenaar 		  }
38839af78769SBram Moolenaar 	    case ISN_CHECKLEN: smsg("%4d CHECKLEN %s%d", current,
38849af78769SBram Moolenaar 				iptr->isn_arg.checklen.cl_more_OK ? ">= " : "",
38859af78769SBram Moolenaar 				iptr->isn_arg.checklen.cl_min_len);
38869af78769SBram Moolenaar 			       break;
38872bb2658bSBram Moolenaar 	    case ISN_COND2BOOL: smsg("%4d COND2BOOL", current); break;
38888a7d6542SBram Moolenaar 	    case ISN_2BOOL: if (iptr->isn_arg.number)
38898a7d6542SBram Moolenaar 				smsg("%4d INVERT (!val)", current);
38908a7d6542SBram Moolenaar 			    else
38918a7d6542SBram Moolenaar 				smsg("%4d 2BOOL (!!val)", current);
38928a7d6542SBram Moolenaar 			    break;
3893db99f9f2SBram Moolenaar 	    case ISN_2STRING: smsg("%4d 2STRING stack[%lld]", current,
3894db99f9f2SBram Moolenaar 					 (long long)(iptr->isn_arg.number));
38958a7d6542SBram Moolenaar 			      break;
3896418f1df5SBram Moolenaar 	    case ISN_2STRING_ANY: smsg("%4d 2STRING_ANY stack[%lld]", current,
3897418f1df5SBram Moolenaar 					 (long long)(iptr->isn_arg.number));
3898418f1df5SBram Moolenaar 			      break;
389908597875SBram Moolenaar 	    case ISN_RANGE: smsg("%4d RANGE %s", current, iptr->isn_arg.string);
390008597875SBram Moolenaar 			    break;
3901c3516f7eSBram Moolenaar 	    case ISN_PUT:
390208597875SBram Moolenaar 	        if (iptr->isn_arg.put.put_lnum == LNUM_VARIABLE_RANGE_ABOVE)
390308597875SBram Moolenaar 		    smsg("%4d PUT %c above range",
390408597875SBram Moolenaar 				       current, iptr->isn_arg.put.put_regname);
390508597875SBram Moolenaar 		else if (iptr->isn_arg.put.put_lnum == LNUM_VARIABLE_RANGE)
390608597875SBram Moolenaar 		    smsg("%4d PUT %c range",
390708597875SBram Moolenaar 				       current, iptr->isn_arg.put.put_regname);
390808597875SBram Moolenaar 		else
390908597875SBram Moolenaar 		    smsg("%4d PUT %c %ld", current,
391008597875SBram Moolenaar 						 iptr->isn_arg.put.put_regname,
3911c3516f7eSBram Moolenaar 					     (long)iptr->isn_arg.put.put_lnum);
3912c3516f7eSBram Moolenaar 		break;
39138a7d6542SBram Moolenaar 
391402194d2bSBram Moolenaar 		// TODO: summarize modifiers
391502194d2bSBram Moolenaar 	    case ISN_CMDMOD:
391602194d2bSBram Moolenaar 		{
391702194d2bSBram Moolenaar 		    char_u  *buf;
3918a360dbe3SBram Moolenaar 		    size_t  len = produce_cmdmods(
391902194d2bSBram Moolenaar 				  NULL, iptr->isn_arg.cmdmod.cf_cmdmod, FALSE);
392002194d2bSBram Moolenaar 
392102194d2bSBram Moolenaar 		    buf = alloc(len + 1);
392202194d2bSBram Moolenaar 		    if (buf != NULL)
392302194d2bSBram Moolenaar 		    {
392402194d2bSBram Moolenaar 			(void)produce_cmdmods(
392502194d2bSBram Moolenaar 				   buf, iptr->isn_arg.cmdmod.cf_cmdmod, FALSE);
392602194d2bSBram Moolenaar 			smsg("%4d CMDMOD %s", current, buf);
392702194d2bSBram Moolenaar 			vim_free(buf);
392802194d2bSBram Moolenaar 		    }
392902194d2bSBram Moolenaar 		    break;
393002194d2bSBram Moolenaar 		}
393102194d2bSBram Moolenaar 	    case ISN_CMDMOD_REV: smsg("%4d CMDMOD_REV", current); break;
3932f4c6e1e7SBram Moolenaar 
3933792f786aSBram Moolenaar 	    case ISN_UNPACK: smsg("%4d UNPACK %d%s", current,
3934792f786aSBram Moolenaar 			iptr->isn_arg.unpack.unp_count,
3935792f786aSBram Moolenaar 			iptr->isn_arg.unpack.unp_semicolon ? " semicolon" : "");
3936792f786aSBram Moolenaar 			      break;
3937389df259SBram Moolenaar 	    case ISN_SHUFFLE: smsg("%4d SHUFFLE %d up %d", current,
3938389df259SBram Moolenaar 					 iptr->isn_arg.shuffle.shfl_item,
3939389df259SBram Moolenaar 					 iptr->isn_arg.shuffle.shfl_up);
3940389df259SBram Moolenaar 			      break;
39418a7d6542SBram Moolenaar 	    case ISN_DROP: smsg("%4d DROP", current); break;
39428a7d6542SBram Moolenaar 	}
3943793dcc54SBram Moolenaar 
3944793dcc54SBram Moolenaar 	out_flush();	    // output one line at a time
3945793dcc54SBram Moolenaar 	ui_breakcheck();
3946793dcc54SBram Moolenaar 	if (got_int)
3947793dcc54SBram Moolenaar 	    break;
39488a7d6542SBram Moolenaar     }
39498a7d6542SBram Moolenaar }
39508a7d6542SBram Moolenaar 
39518a7d6542SBram Moolenaar /*
395213106605SBram Moolenaar  * Return TRUE when "tv" is not falsy: non-zero, non-empty string, non-empty
39538a7d6542SBram Moolenaar  * list, etc.  Mostly like what JavaScript does, except that empty list and
39548a7d6542SBram Moolenaar  * empty dictionary are FALSE.
39558a7d6542SBram Moolenaar  */
39568a7d6542SBram Moolenaar     int
39578a7d6542SBram Moolenaar tv2bool(typval_T *tv)
39588a7d6542SBram Moolenaar {
39598a7d6542SBram Moolenaar     switch (tv->v_type)
39608a7d6542SBram Moolenaar     {
39618a7d6542SBram Moolenaar 	case VAR_NUMBER:
39628a7d6542SBram Moolenaar 	    return tv->vval.v_number != 0;
39638a7d6542SBram Moolenaar 	case VAR_FLOAT:
39648a7d6542SBram Moolenaar #ifdef FEAT_FLOAT
39658a7d6542SBram Moolenaar 	    return tv->vval.v_float != 0.0;
39668a7d6542SBram Moolenaar #else
39678a7d6542SBram Moolenaar 	    break;
39688a7d6542SBram Moolenaar #endif
39698a7d6542SBram Moolenaar 	case VAR_PARTIAL:
39708a7d6542SBram Moolenaar 	    return tv->vval.v_partial != NULL;
39718a7d6542SBram Moolenaar 	case VAR_FUNC:
39728a7d6542SBram Moolenaar 	case VAR_STRING:
39738a7d6542SBram Moolenaar 	    return tv->vval.v_string != NULL && *tv->vval.v_string != NUL;
39748a7d6542SBram Moolenaar 	case VAR_LIST:
39758a7d6542SBram Moolenaar 	    return tv->vval.v_list != NULL && tv->vval.v_list->lv_len > 0;
39768a7d6542SBram Moolenaar 	case VAR_DICT:
39778a7d6542SBram Moolenaar 	    return tv->vval.v_dict != NULL
39788a7d6542SBram Moolenaar 				    && tv->vval.v_dict->dv_hashtab.ht_used > 0;
39798a7d6542SBram Moolenaar 	case VAR_BOOL:
39808a7d6542SBram Moolenaar 	case VAR_SPECIAL:
39818a7d6542SBram Moolenaar 	    return tv->vval.v_number == VVAL_TRUE ? TRUE : FALSE;
39828a7d6542SBram Moolenaar 	case VAR_JOB:
39838a7d6542SBram Moolenaar #ifdef FEAT_JOB_CHANNEL
39848a7d6542SBram Moolenaar 	    return tv->vval.v_job != NULL;
39858a7d6542SBram Moolenaar #else
39868a7d6542SBram Moolenaar 	    break;
39878a7d6542SBram Moolenaar #endif
39888a7d6542SBram Moolenaar 	case VAR_CHANNEL:
39898a7d6542SBram Moolenaar #ifdef FEAT_JOB_CHANNEL
39908a7d6542SBram Moolenaar 	    return tv->vval.v_channel != NULL;
39918a7d6542SBram Moolenaar #else
39928a7d6542SBram Moolenaar 	    break;
39938a7d6542SBram Moolenaar #endif
39948a7d6542SBram Moolenaar 	case VAR_BLOB:
39958a7d6542SBram Moolenaar 	    return tv->vval.v_blob != NULL && tv->vval.v_blob->bv_ga.ga_len > 0;
39968a7d6542SBram Moolenaar 	case VAR_UNKNOWN:
39974c683750SBram Moolenaar 	case VAR_ANY:
39988a7d6542SBram Moolenaar 	case VAR_VOID:
39998a7d6542SBram Moolenaar 	    break;
40008a7d6542SBram Moolenaar     }
40018a7d6542SBram Moolenaar     return FALSE;
40028a7d6542SBram Moolenaar }
40038a7d6542SBram Moolenaar 
4004ea2d407fSBram Moolenaar     void
4005ea2d407fSBram Moolenaar emsg_using_string_as(typval_T *tv, int as_number)
4006ea2d407fSBram Moolenaar {
4007ea2d407fSBram Moolenaar     semsg(_(as_number ? e_using_string_as_number_str
4008ea2d407fSBram Moolenaar 						 : e_using_string_as_bool_str),
4009ea2d407fSBram Moolenaar 		       tv->vval.v_string == NULL
4010ea2d407fSBram Moolenaar 					   ? (char_u *)"" : tv->vval.v_string);
4011ea2d407fSBram Moolenaar }
4012ea2d407fSBram Moolenaar 
40138a7d6542SBram Moolenaar /*
40148a7d6542SBram Moolenaar  * If "tv" is a string give an error and return FAIL.
40158a7d6542SBram Moolenaar  */
40168a7d6542SBram Moolenaar     int
40178a7d6542SBram Moolenaar check_not_string(typval_T *tv)
40188a7d6542SBram Moolenaar {
40198a7d6542SBram Moolenaar     if (tv->v_type == VAR_STRING)
40208a7d6542SBram Moolenaar     {
4021ea2d407fSBram Moolenaar 	emsg_using_string_as(tv, TRUE);
40228a7d6542SBram Moolenaar 	clear_tv(tv);
40238a7d6542SBram Moolenaar 	return FAIL;
40248a7d6542SBram Moolenaar     }
40258a7d6542SBram Moolenaar     return OK;
40268a7d6542SBram Moolenaar }
40278a7d6542SBram Moolenaar 
40288a7d6542SBram Moolenaar 
40298a7d6542SBram Moolenaar #endif // FEAT_EVAL
4030