xref: /vim-8.2.3635/src/vim9execute.c (revision 65b9545f)
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  */
578a7d6542SBram Moolenaar typedef struct {
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
708a7d6542SBram Moolenaar } ectx_T;
718a7d6542SBram Moolenaar 
728a7d6542SBram Moolenaar // Get pointer to item relative to the bottom of the stack, -1 is the last one.
738a7d6542SBram Moolenaar #define STACK_TV_BOT(idx) (((typval_T *)ectx->ec_stack.ga_data) + ectx->ec_stack.ga_len + idx)
748a7d6542SBram Moolenaar 
758a7d6542SBram Moolenaar /*
76170fcfcfSBram Moolenaar  * Return the number of arguments, including optional arguments and any vararg.
778a7d6542SBram Moolenaar  */
788a7d6542SBram Moolenaar     static int
798a7d6542SBram Moolenaar ufunc_argcount(ufunc_T *ufunc)
808a7d6542SBram Moolenaar {
818a7d6542SBram Moolenaar     return ufunc->uf_args.ga_len + (ufunc->uf_va_name != NULL ? 1 : 0);
828a7d6542SBram Moolenaar }
838a7d6542SBram Moolenaar 
848a7d6542SBram Moolenaar /*
85170fcfcfSBram Moolenaar  * Set the instruction index, depending on omitted arguments, where the default
86170fcfcfSBram Moolenaar  * values are to be computed.  If all optional arguments are present, start
87170fcfcfSBram Moolenaar  * with the function body.
88170fcfcfSBram Moolenaar  * The expression evaluation is at the start of the instructions:
89170fcfcfSBram Moolenaar  *  0 ->  EVAL default1
90170fcfcfSBram Moolenaar  *	       STORE arg[-2]
91170fcfcfSBram Moolenaar  *  1 ->  EVAL default2
92170fcfcfSBram Moolenaar  *	       STORE arg[-1]
93170fcfcfSBram Moolenaar  *  2 ->  function body
94170fcfcfSBram Moolenaar  */
95170fcfcfSBram Moolenaar     static void
96170fcfcfSBram Moolenaar init_instr_idx(ufunc_T *ufunc, int argcount, ectx_T *ectx)
97170fcfcfSBram Moolenaar {
98170fcfcfSBram Moolenaar     if (ufunc->uf_def_args.ga_len == 0)
99170fcfcfSBram Moolenaar 	ectx->ec_iidx = 0;
100170fcfcfSBram Moolenaar     else
101170fcfcfSBram Moolenaar     {
102170fcfcfSBram Moolenaar 	int	defcount = ufunc->uf_args.ga_len - argcount;
103170fcfcfSBram Moolenaar 
104170fcfcfSBram Moolenaar 	// If there is a varargs argument defcount can be negative, no defaults
105170fcfcfSBram Moolenaar 	// to evaluate then.
106170fcfcfSBram Moolenaar 	if (defcount < 0)
107170fcfcfSBram Moolenaar 	    defcount = 0;
108170fcfcfSBram Moolenaar 	ectx->ec_iidx = ufunc->uf_def_arg_idx[
109170fcfcfSBram Moolenaar 					 ufunc->uf_def_args.ga_len - defcount];
110170fcfcfSBram Moolenaar     }
111170fcfcfSBram Moolenaar }
112170fcfcfSBram Moolenaar 
113170fcfcfSBram Moolenaar /*
114fe270817SBram Moolenaar  * Create a new list from "count" items at the bottom of the stack.
115fe270817SBram Moolenaar  * When "count" is zero an empty list is added to the stack.
116fe270817SBram Moolenaar  */
117fe270817SBram Moolenaar     static int
118fe270817SBram Moolenaar exe_newlist(int count, ectx_T *ectx)
119fe270817SBram Moolenaar {
120fe270817SBram Moolenaar     list_T	*list = list_alloc_with_items(count);
121fe270817SBram Moolenaar     int		idx;
122fe270817SBram Moolenaar     typval_T	*tv;
123fe270817SBram Moolenaar 
124fe270817SBram Moolenaar     if (list == NULL)
125fe270817SBram Moolenaar 	return FAIL;
126fe270817SBram Moolenaar     for (idx = 0; idx < count; ++idx)
127fe270817SBram Moolenaar 	list_set_item(list, idx, STACK_TV_BOT(idx - count));
128fe270817SBram Moolenaar 
129fe270817SBram Moolenaar     if (count > 0)
130fe270817SBram Moolenaar 	ectx->ec_stack.ga_len -= count - 1;
131270d0388SBram Moolenaar     else if (GA_GROW(&ectx->ec_stack, 1) == FAIL)
132fe270817SBram Moolenaar 	return FAIL;
133fe270817SBram Moolenaar     else
134fe270817SBram Moolenaar 	++ectx->ec_stack.ga_len;
135fe270817SBram Moolenaar     tv = STACK_TV_BOT(-1);
136fe270817SBram Moolenaar     tv->v_type = VAR_LIST;
137fe270817SBram Moolenaar     tv->vval.v_list = list;
138fe270817SBram Moolenaar     ++list->lv_refcount;
139fe270817SBram Moolenaar     return OK;
140fe270817SBram Moolenaar }
141fe270817SBram Moolenaar 
142fe270817SBram Moolenaar /*
1438a7d6542SBram Moolenaar  * Call compiled function "cdf_idx" from compiled code.
1448a7d6542SBram Moolenaar  *
1458a7d6542SBram Moolenaar  * Stack has:
1468a7d6542SBram Moolenaar  * - current arguments (already there)
1478a7d6542SBram Moolenaar  * - omitted optional argument (default values) added here
1488a7d6542SBram Moolenaar  * - stack frame:
1498a7d6542SBram Moolenaar  *	- pointer to calling function
1508a7d6542SBram Moolenaar  *	- Index of next instruction in calling function
1518a7d6542SBram Moolenaar  *	- previous frame pointer
1528a7d6542SBram Moolenaar  * - reserved space for local variables
1538a7d6542SBram Moolenaar  */
1548a7d6542SBram Moolenaar     static int
1551378fbc4SBram Moolenaar call_dfunc(int cdf_idx, int argcount_arg, ectx_T *ectx)
1568a7d6542SBram Moolenaar {
1571378fbc4SBram Moolenaar     int	    argcount = argcount_arg;
1588a7d6542SBram Moolenaar     dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data) + cdf_idx;
1598a7d6542SBram Moolenaar     ufunc_T *ufunc = dfunc->df_ufunc;
1601378fbc4SBram Moolenaar     int	    arg_to_add;
1611378fbc4SBram Moolenaar     int	    vararg_count = 0;
1628a7d6542SBram Moolenaar     int	    idx;
163c620c055SBram Moolenaar     estack_T *entry;
1648a7d6542SBram Moolenaar 
1658a7d6542SBram Moolenaar     if (dfunc->df_deleted)
1668a7d6542SBram Moolenaar     {
1678a7d6542SBram Moolenaar 	emsg_funcname(e_func_deleted, ufunc->uf_name);
1688a7d6542SBram Moolenaar 	return FAIL;
1698a7d6542SBram Moolenaar     }
1708a7d6542SBram Moolenaar 
1711378fbc4SBram Moolenaar     if (ufunc->uf_va_name != NULL)
1721378fbc4SBram Moolenaar     {
173fe270817SBram Moolenaar 	// Need to make a list out of the vararg arguments.
1741378fbc4SBram Moolenaar 	// Stack at time of call with 2 varargs:
1751378fbc4SBram Moolenaar 	//   normal_arg
1761378fbc4SBram Moolenaar 	//   optional_arg
1771378fbc4SBram Moolenaar 	//   vararg_1
1781378fbc4SBram Moolenaar 	//   vararg_2
179fe270817SBram Moolenaar 	// After creating the list:
1801378fbc4SBram Moolenaar 	//   normal_arg
1811378fbc4SBram Moolenaar 	//   optional_arg
182fe270817SBram Moolenaar 	//   vararg-list
183fe270817SBram Moolenaar 	// With missing optional arguments we get:
184fe270817SBram Moolenaar 	//    normal_arg
185fe270817SBram Moolenaar 	// After creating the list
186fe270817SBram Moolenaar 	//    normal_arg
187fe270817SBram Moolenaar 	//    (space for optional_arg)
188fe270817SBram Moolenaar 	//    vararg-list
1891378fbc4SBram Moolenaar 	vararg_count = argcount - ufunc->uf_args.ga_len;
1901378fbc4SBram Moolenaar 	if (vararg_count < 0)
1911378fbc4SBram Moolenaar 	    vararg_count = 0;
1921378fbc4SBram Moolenaar 	else
1931378fbc4SBram Moolenaar 	    argcount -= vararg_count;
194fe270817SBram Moolenaar 	if (exe_newlist(vararg_count, ectx) == FAIL)
1951378fbc4SBram Moolenaar 	    return FAIL;
196fe270817SBram Moolenaar 
197fe270817SBram Moolenaar 	vararg_count = 1;
1981378fbc4SBram Moolenaar     }
1991378fbc4SBram Moolenaar 
200fe270817SBram Moolenaar     arg_to_add = ufunc->uf_args.ga_len - argcount;
2011378fbc4SBram Moolenaar     if (arg_to_add < 0)
2021378fbc4SBram Moolenaar     {
2031378fbc4SBram Moolenaar 	iemsg("Argument count wrong?");
2041378fbc4SBram Moolenaar 	return FAIL;
2051378fbc4SBram Moolenaar     }
206bf67ea1aSBram Moolenaar     if (ga_grow(&ectx->ec_stack, arg_to_add + 3
207bf67ea1aSBram Moolenaar 		       + dfunc->df_varcount + dfunc->df_closure_count) == FAIL)
2088a7d6542SBram Moolenaar 	return FAIL;
2098a7d6542SBram Moolenaar 
210fe270817SBram Moolenaar     // Move the vararg-list to below the missing optional arguments.
211fe270817SBram Moolenaar     if (vararg_count > 0 && arg_to_add > 0)
212fe270817SBram Moolenaar 	*STACK_TV_BOT(arg_to_add - 1) = *STACK_TV_BOT(-1);
213170fcfcfSBram Moolenaar 
214170fcfcfSBram Moolenaar     // Reserve space for omitted optional arguments, filled in soon.
2151378fbc4SBram Moolenaar     for (idx = 0; idx < arg_to_add; ++idx)
216fe270817SBram Moolenaar 	STACK_TV_BOT(idx - vararg_count)->v_type = VAR_UNKNOWN;
2171378fbc4SBram Moolenaar     ectx->ec_stack.ga_len += arg_to_add;
2188a7d6542SBram Moolenaar 
2198a7d6542SBram Moolenaar     // Store current execution state in stack frame for ISN_RETURN.
2208a7d6542SBram Moolenaar     STACK_TV_BOT(0)->vval.v_number = ectx->ec_dfunc_idx;
2218a7d6542SBram Moolenaar     STACK_TV_BOT(1)->vval.v_number = ectx->ec_iidx;
222bf67ea1aSBram Moolenaar     STACK_TV_BOT(2)->vval.v_number = ectx->ec_frame_idx;
223bf67ea1aSBram Moolenaar     ectx->ec_frame_idx = ectx->ec_stack.ga_len;
2248a7d6542SBram Moolenaar 
2258a7d6542SBram Moolenaar     // Initialize local variables
226bf67ea1aSBram Moolenaar     for (idx = 0; idx < dfunc->df_varcount + dfunc->df_closure_count; ++idx)
2278a7d6542SBram Moolenaar 	STACK_TV_BOT(STACK_FRAME_SIZE + idx)->v_type = VAR_UNKNOWN;
228bf67ea1aSBram Moolenaar     ectx->ec_stack.ga_len += STACK_FRAME_SIZE
229bf67ea1aSBram Moolenaar 				+ dfunc->df_varcount + dfunc->df_closure_count;
2308a7d6542SBram Moolenaar 
2318a7d6542SBram Moolenaar     // Set execution state to the start of the called function.
2328a7d6542SBram Moolenaar     ectx->ec_dfunc_idx = cdf_idx;
2338a7d6542SBram Moolenaar     ectx->ec_instr = dfunc->df_instr;
234c620c055SBram Moolenaar     entry = estack_push_ufunc(dfunc->df_ufunc, 1);
235c620c055SBram Moolenaar     if (entry != NULL)
236c620c055SBram Moolenaar     {
237c620c055SBram Moolenaar 	// Set the script context to the script where the function was defined.
238c620c055SBram Moolenaar 	// TODO: save more than the SID?
239c620c055SBram Moolenaar 	entry->es_save_sid = current_sctx.sc_sid;
240c620c055SBram Moolenaar 	current_sctx.sc_sid = ufunc->uf_script_ctx.sc_sid;
241c620c055SBram Moolenaar     }
242170fcfcfSBram Moolenaar 
243170fcfcfSBram Moolenaar     // Decide where to start execution, handles optional arguments.
244170fcfcfSBram Moolenaar     init_instr_idx(ufunc, argcount, ectx);
2458a7d6542SBram Moolenaar 
2468a7d6542SBram Moolenaar     return OK;
2478a7d6542SBram Moolenaar }
2488a7d6542SBram Moolenaar 
2498a7d6542SBram Moolenaar // Get pointer to item in the stack.
2508a7d6542SBram Moolenaar #define STACK_TV(idx) (((typval_T *)ectx->ec_stack.ga_data) + idx)
2518a7d6542SBram Moolenaar 
2528a7d6542SBram Moolenaar /*
253bf67ea1aSBram Moolenaar  * Used when returning from a function: Check if any closure is still
254bf67ea1aSBram Moolenaar  * referenced.  If so then move the arguments and variables to a separate piece
255bf67ea1aSBram Moolenaar  * of stack to be used when the closure is called.
256bf67ea1aSBram Moolenaar  * When "free_arguments" is TRUE the arguments are to be freed.
257bf67ea1aSBram Moolenaar  * Returns FAIL when out of memory.
258bf67ea1aSBram Moolenaar  */
259bf67ea1aSBram Moolenaar     static int
260bf67ea1aSBram Moolenaar handle_closure_in_use(ectx_T *ectx, int free_arguments)
261bf67ea1aSBram Moolenaar {
262bf67ea1aSBram Moolenaar     dfunc_T	*dfunc = ((dfunc_T *)def_functions.ga_data)
263bf67ea1aSBram Moolenaar 							  + ectx->ec_dfunc_idx;
264bf67ea1aSBram Moolenaar     int		argcount = ufunc_argcount(dfunc->df_ufunc);
265bf67ea1aSBram Moolenaar     int		top = ectx->ec_frame_idx - argcount;
266bf67ea1aSBram Moolenaar     int		idx;
267bf67ea1aSBram Moolenaar     typval_T	*tv;
268bf67ea1aSBram Moolenaar     int		closure_in_use = FALSE;
269bf67ea1aSBram Moolenaar 
270bf67ea1aSBram Moolenaar     // Check if any created closure is still in use.
271bf67ea1aSBram Moolenaar     for (idx = 0; idx < dfunc->df_closure_count; ++idx)
272bf67ea1aSBram Moolenaar     {
273bf67ea1aSBram Moolenaar 	tv = STACK_TV(ectx->ec_frame_idx + STACK_FRAME_SIZE
274bf67ea1aSBram Moolenaar 						   + dfunc->df_varcount + idx);
275221fcc74SBram Moolenaar 	if (tv->v_type == VAR_PARTIAL && tv->vval.v_partial != NULL
276221fcc74SBram Moolenaar 					&& tv->vval.v_partial->pt_refcount > 1)
277221fcc74SBram Moolenaar 	{
278221fcc74SBram Moolenaar 	    int refcount = tv->vval.v_partial->pt_refcount;
279221fcc74SBram Moolenaar 	    int i;
280221fcc74SBram Moolenaar 
281f821ddaaSBram Moolenaar 	    // A Reference in a local variables doesn't count, it gets
282221fcc74SBram Moolenaar 	    // unreferenced on return.
283221fcc74SBram Moolenaar 	    for (i = 0; i < dfunc->df_varcount; ++i)
284221fcc74SBram Moolenaar 	    {
285221fcc74SBram Moolenaar 		typval_T *stv = STACK_TV(ectx->ec_frame_idx
286221fcc74SBram Moolenaar 						       + STACK_FRAME_SIZE + i);
287221fcc74SBram Moolenaar 		if (stv->v_type == VAR_PARTIAL
288221fcc74SBram Moolenaar 				  && tv->vval.v_partial == stv->vval.v_partial)
289221fcc74SBram Moolenaar 		    --refcount;
290221fcc74SBram Moolenaar 	    }
291221fcc74SBram Moolenaar 	    if (refcount > 1)
292f7779c63SBram Moolenaar 	    {
293bf67ea1aSBram Moolenaar 		closure_in_use = TRUE;
294f7779c63SBram Moolenaar 		break;
295f7779c63SBram Moolenaar 	    }
296bf67ea1aSBram Moolenaar 	}
297221fcc74SBram Moolenaar     }
298bf67ea1aSBram Moolenaar 
299bf67ea1aSBram Moolenaar     if (closure_in_use)
300bf67ea1aSBram Moolenaar     {
301bf67ea1aSBram Moolenaar 	funcstack_T *funcstack = ALLOC_CLEAR_ONE(funcstack_T);
302bf67ea1aSBram Moolenaar 	typval_T    *stack;
303bf67ea1aSBram Moolenaar 
304bf67ea1aSBram Moolenaar 	// A closure is using the arguments and/or local variables.
305bf67ea1aSBram Moolenaar 	// Move them to the called function.
306bf67ea1aSBram Moolenaar 	if (funcstack == NULL)
307bf67ea1aSBram Moolenaar 	    return FAIL;
308bf67ea1aSBram Moolenaar 	funcstack->fs_ga.ga_len = argcount + STACK_FRAME_SIZE
309bf67ea1aSBram Moolenaar 							  + dfunc->df_varcount;
310bf67ea1aSBram Moolenaar 	stack = ALLOC_CLEAR_MULT(typval_T, funcstack->fs_ga.ga_len);
311bf67ea1aSBram Moolenaar 	funcstack->fs_ga.ga_data = stack;
312bf67ea1aSBram Moolenaar 	if (stack == NULL)
313bf67ea1aSBram Moolenaar 	{
314bf67ea1aSBram Moolenaar 	    vim_free(funcstack);
315bf67ea1aSBram Moolenaar 	    return FAIL;
316bf67ea1aSBram Moolenaar 	}
317bf67ea1aSBram Moolenaar 
318bf67ea1aSBram Moolenaar 	// Move or copy the arguments.
319bf67ea1aSBram Moolenaar 	for (idx = 0; idx < argcount; ++idx)
320bf67ea1aSBram Moolenaar 	{
321bf67ea1aSBram Moolenaar 	    tv = STACK_TV(top + idx);
322bf67ea1aSBram Moolenaar 	    if (free_arguments)
323bf67ea1aSBram Moolenaar 	    {
324bf67ea1aSBram Moolenaar 		*(stack + idx) = *tv;
325bf67ea1aSBram Moolenaar 		tv->v_type = VAR_UNKNOWN;
326bf67ea1aSBram Moolenaar 	    }
327bf67ea1aSBram Moolenaar 	    else
328bf67ea1aSBram Moolenaar 		copy_tv(tv, stack + idx);
329bf67ea1aSBram Moolenaar 	}
330bf67ea1aSBram Moolenaar 	// Move the local variables.
331bf67ea1aSBram Moolenaar 	for (idx = 0; idx < dfunc->df_varcount; ++idx)
332bf67ea1aSBram Moolenaar 	{
333bf67ea1aSBram Moolenaar 	    tv = STACK_TV(ectx->ec_frame_idx + STACK_FRAME_SIZE + idx);
334f821ddaaSBram Moolenaar 
335f821ddaaSBram Moolenaar 	    // Do not copy a partial created for a local function.
336f821ddaaSBram Moolenaar 	    // TODO: this won't work if the closure actually uses it.  But when
337f821ddaaSBram Moolenaar 	    // keeping it it gets complicated: it will create a reference cycle
338f821ddaaSBram Moolenaar 	    // inside the partial, thus needs special handling for garbage
339f821ddaaSBram Moolenaar 	    // collection.
340f821ddaaSBram Moolenaar 	    if (tv->v_type == VAR_PARTIAL && tv->vval.v_partial != NULL)
341f821ddaaSBram Moolenaar 	    {
342f821ddaaSBram Moolenaar 		int i;
343f821ddaaSBram Moolenaar 		typval_T *ctv;
344f821ddaaSBram Moolenaar 
345f821ddaaSBram Moolenaar 		for (i = 0; i < dfunc->df_closure_count; ++i)
346f821ddaaSBram Moolenaar 		{
347f821ddaaSBram Moolenaar 		    ctv = STACK_TV(ectx->ec_frame_idx + STACK_FRAME_SIZE
348f821ddaaSBram Moolenaar 						     + dfunc->df_varcount + i);
349f821ddaaSBram Moolenaar 		    if (tv->vval.v_partial == ctv->vval.v_partial)
350f821ddaaSBram Moolenaar 			break;
351f821ddaaSBram Moolenaar 		}
352f821ddaaSBram Moolenaar 		if (i < dfunc->df_closure_count)
353f821ddaaSBram Moolenaar 		{
354f821ddaaSBram Moolenaar 		    (stack + argcount + STACK_FRAME_SIZE + idx)->v_type =
355f821ddaaSBram Moolenaar 								   VAR_UNKNOWN;
356f821ddaaSBram Moolenaar 		    continue;
357f821ddaaSBram Moolenaar 		}
358f821ddaaSBram Moolenaar 	    }
359f821ddaaSBram Moolenaar 
360bf67ea1aSBram Moolenaar 	    *(stack + argcount + STACK_FRAME_SIZE + idx) = *tv;
361bf67ea1aSBram Moolenaar 	    tv->v_type = VAR_UNKNOWN;
362bf67ea1aSBram Moolenaar 	}
363bf67ea1aSBram Moolenaar 
364bf67ea1aSBram Moolenaar 	for (idx = 0; idx < dfunc->df_closure_count; ++idx)
365bf67ea1aSBram Moolenaar 	{
366bf67ea1aSBram Moolenaar 	    tv = STACK_TV(ectx->ec_frame_idx + STACK_FRAME_SIZE
367bf67ea1aSBram Moolenaar 						   + dfunc->df_varcount + idx);
368f7779c63SBram Moolenaar 	    if (tv->v_type == VAR_PARTIAL)
369bf67ea1aSBram Moolenaar 	    {
370f7779c63SBram Moolenaar 		partial_T *partial = tv->vval.v_partial;
371f7779c63SBram Moolenaar 
372f7779c63SBram Moolenaar 		if (partial->pt_refcount > 1)
373f7779c63SBram Moolenaar 		{
374bf67ea1aSBram Moolenaar 		    ++funcstack->fs_refcount;
375f7779c63SBram Moolenaar 		    partial->pt_funcstack = funcstack;
376f7779c63SBram Moolenaar 		    partial->pt_ectx_stack = &funcstack->fs_ga;
377f7779c63SBram Moolenaar 		    partial->pt_ectx_frame = ectx->ec_frame_idx - top;
378f7779c63SBram Moolenaar 		}
379bf67ea1aSBram Moolenaar 	    }
380bf67ea1aSBram Moolenaar 	}
381bf67ea1aSBram Moolenaar     }
382bf67ea1aSBram Moolenaar 
383bf67ea1aSBram Moolenaar     return OK;
384bf67ea1aSBram Moolenaar }
385bf67ea1aSBram Moolenaar 
386bf67ea1aSBram Moolenaar /*
3878a7d6542SBram Moolenaar  * Return from the current function.
3888a7d6542SBram Moolenaar  */
389bf67ea1aSBram Moolenaar     static int
3908a7d6542SBram Moolenaar func_return(ectx_T *ectx)
3918a7d6542SBram Moolenaar {
3928a7d6542SBram Moolenaar     int		idx;
393bf67ea1aSBram Moolenaar     dfunc_T	*dfunc = ((dfunc_T *)def_functions.ga_data)
394bf67ea1aSBram Moolenaar 							  + ectx->ec_dfunc_idx;
395bf67ea1aSBram Moolenaar     int		argcount = ufunc_argcount(dfunc->df_ufunc);
396bf67ea1aSBram Moolenaar     int		top = ectx->ec_frame_idx - argcount;
397c620c055SBram Moolenaar     estack_T	*entry;
3988a7d6542SBram Moolenaar 
3998a7d6542SBram Moolenaar     // execution context goes one level up
400c620c055SBram Moolenaar     entry = estack_pop();
401c620c055SBram Moolenaar     if (entry != NULL)
402c620c055SBram Moolenaar 	current_sctx.sc_sid = entry->es_save_sid;
4038a7d6542SBram Moolenaar 
404bf67ea1aSBram Moolenaar     if (handle_closure_in_use(ectx, TRUE) == FAIL)
405bf67ea1aSBram Moolenaar 	return FAIL;
406bf67ea1aSBram Moolenaar 
407bf67ea1aSBram Moolenaar     // Clear the arguments.
408bf67ea1aSBram Moolenaar     for (idx = top; idx < ectx->ec_frame_idx; ++idx)
409bf67ea1aSBram Moolenaar 	clear_tv(STACK_TV(idx));
410bf67ea1aSBram Moolenaar 
411bf67ea1aSBram Moolenaar     // Clear local variables and temp values, but not the return value.
412bf67ea1aSBram Moolenaar     for (idx = ectx->ec_frame_idx + STACK_FRAME_SIZE;
4138a7d6542SBram Moolenaar 					idx < ectx->ec_stack.ga_len - 1; ++idx)
4148a7d6542SBram Moolenaar 	clear_tv(STACK_TV(idx));
415170fcfcfSBram Moolenaar 
416170fcfcfSBram Moolenaar     // Restore the previous frame.
417bf67ea1aSBram Moolenaar     ectx->ec_dfunc_idx = STACK_TV(ectx->ec_frame_idx)->vval.v_number;
418bf67ea1aSBram Moolenaar     ectx->ec_iidx = STACK_TV(ectx->ec_frame_idx + 1)->vval.v_number;
419bf67ea1aSBram Moolenaar     ectx->ec_frame_idx = STACK_TV(ectx->ec_frame_idx + 2)->vval.v_number;
4208a7d6542SBram Moolenaar     dfunc = ((dfunc_T *)def_functions.ga_data) + ectx->ec_dfunc_idx;
4218a7d6542SBram Moolenaar     ectx->ec_instr = dfunc->df_instr;
422170fcfcfSBram Moolenaar 
423170fcfcfSBram Moolenaar     // Reset the stack to the position before the call, move the return value
424170fcfcfSBram Moolenaar     // to the top of the stack.
425170fcfcfSBram Moolenaar     idx = ectx->ec_stack.ga_len - 1;
426170fcfcfSBram Moolenaar     ectx->ec_stack.ga_len = top + 1;
427170fcfcfSBram Moolenaar     *STACK_TV_BOT(-1) = *STACK_TV(idx);
428bf67ea1aSBram Moolenaar 
429bf67ea1aSBram Moolenaar     return OK;
4308a7d6542SBram Moolenaar }
4318a7d6542SBram Moolenaar 
4328a7d6542SBram Moolenaar #undef STACK_TV
4338a7d6542SBram Moolenaar 
4348a7d6542SBram Moolenaar /*
4358a7d6542SBram Moolenaar  * Prepare arguments and rettv for calling a builtin or user function.
4368a7d6542SBram Moolenaar  */
4378a7d6542SBram Moolenaar     static int
4388a7d6542SBram Moolenaar call_prepare(int argcount, typval_T *argvars, ectx_T *ectx)
4398a7d6542SBram Moolenaar {
4408a7d6542SBram Moolenaar     int		idx;
4418a7d6542SBram Moolenaar     typval_T	*tv;
4428a7d6542SBram Moolenaar 
4438a7d6542SBram Moolenaar     // Move arguments from bottom of the stack to argvars[] and add terminator.
4448a7d6542SBram Moolenaar     for (idx = 0; idx < argcount; ++idx)
4458a7d6542SBram Moolenaar 	argvars[idx] = *STACK_TV_BOT(idx - argcount);
4468a7d6542SBram Moolenaar     argvars[argcount].v_type = VAR_UNKNOWN;
4478a7d6542SBram Moolenaar 
4488a7d6542SBram Moolenaar     // Result replaces the arguments on the stack.
4498a7d6542SBram Moolenaar     if (argcount > 0)
4508a7d6542SBram Moolenaar 	ectx->ec_stack.ga_len -= argcount - 1;
451270d0388SBram Moolenaar     else if (GA_GROW(&ectx->ec_stack, 1) == FAIL)
4528a7d6542SBram Moolenaar 	return FAIL;
4538a7d6542SBram Moolenaar     else
4548a7d6542SBram Moolenaar 	++ectx->ec_stack.ga_len;
4558a7d6542SBram Moolenaar 
4568a7d6542SBram Moolenaar     // Default return value is zero.
4578a7d6542SBram Moolenaar     tv = STACK_TV_BOT(-1);
4588a7d6542SBram Moolenaar     tv->v_type = VAR_NUMBER;
4598a7d6542SBram Moolenaar     tv->vval.v_number = 0;
4608a7d6542SBram Moolenaar 
4618a7d6542SBram Moolenaar     return OK;
4628a7d6542SBram Moolenaar }
4638a7d6542SBram Moolenaar 
46408f7a41bSBram Moolenaar // Ugly global to avoid passing the execution context around through many
46508f7a41bSBram Moolenaar // layers.
46608f7a41bSBram Moolenaar static ectx_T *current_ectx = NULL;
46708f7a41bSBram Moolenaar 
4688a7d6542SBram Moolenaar /*
4698a7d6542SBram Moolenaar  * Call a builtin function by index.
4708a7d6542SBram Moolenaar  */
4718a7d6542SBram Moolenaar     static int
4728a7d6542SBram Moolenaar call_bfunc(int func_idx, int argcount, ectx_T *ectx)
4738a7d6542SBram Moolenaar {
4748a7d6542SBram Moolenaar     typval_T	argvars[MAX_FUNC_ARGS];
4758a7d6542SBram Moolenaar     int		idx;
4768a1c1013SBram Moolenaar     int		did_emsg_before = did_emsg;
47708f7a41bSBram Moolenaar     ectx_T	*prev_ectx = current_ectx;
4788a7d6542SBram Moolenaar 
4798a7d6542SBram Moolenaar     if (call_prepare(argcount, argvars, ectx) == FAIL)
4808a7d6542SBram Moolenaar 	return FAIL;
4818a7d6542SBram Moolenaar 
48208f7a41bSBram Moolenaar     // Call the builtin function.  Set "current_ectx" so that when it
48308f7a41bSBram Moolenaar     // recursively invokes call_def_function() a closure context can be set.
48408f7a41bSBram Moolenaar     current_ectx = ectx;
4858a7d6542SBram Moolenaar     call_internal_func_by_idx(func_idx, argvars, STACK_TV_BOT(-1));
48608f7a41bSBram Moolenaar     current_ectx = prev_ectx;
4878a7d6542SBram Moolenaar 
4888a7d6542SBram Moolenaar     // Clear the arguments.
4898a7d6542SBram Moolenaar     for (idx = 0; idx < argcount; ++idx)
4908a7d6542SBram Moolenaar 	clear_tv(&argvars[idx]);
491015f4267SBram Moolenaar 
4928a1c1013SBram Moolenaar     if (did_emsg != did_emsg_before)
493015f4267SBram Moolenaar 	return FAIL;
4948a7d6542SBram Moolenaar     return OK;
4958a7d6542SBram Moolenaar }
4968a7d6542SBram Moolenaar 
4978a7d6542SBram Moolenaar /*
4988a7d6542SBram Moolenaar  * Execute a user defined function.
4997eeefd4aSBram Moolenaar  * "iptr" can be used to replace the instruction with a more efficient one.
5008a7d6542SBram Moolenaar  */
5018a7d6542SBram Moolenaar     static int
5027eeefd4aSBram Moolenaar call_ufunc(ufunc_T *ufunc, int argcount, ectx_T *ectx, isn_T *iptr)
5038a7d6542SBram Moolenaar {
5048a7d6542SBram Moolenaar     typval_T	argvars[MAX_FUNC_ARGS];
5058a7d6542SBram Moolenaar     funcexe_T   funcexe;
5068a7d6542SBram Moolenaar     int		error;
5078a7d6542SBram Moolenaar     int		idx;
5088a7d6542SBram Moolenaar 
5090cb5bcf5SBram Moolenaar     if (ufunc->uf_def_status == UF_TO_BE_COMPILED
510822ba247SBram Moolenaar 	    && compile_def_function(ufunc, FALSE, NULL) == FAIL)
511822ba247SBram Moolenaar 	return FAIL;
5120cb5bcf5SBram Moolenaar     if (ufunc->uf_def_status == UF_COMPILED)
5137eeefd4aSBram Moolenaar     {
5147eeefd4aSBram Moolenaar 	// The function has been compiled, can call it quickly.  For a function
5157eeefd4aSBram Moolenaar 	// that was defined later: we can call it directly next time.
5167eeefd4aSBram Moolenaar 	if (iptr != NULL)
5177eeefd4aSBram Moolenaar 	{
51820431c9dSBram Moolenaar 	    delete_instr(iptr);
5197eeefd4aSBram Moolenaar 	    iptr->isn_type = ISN_DCALL;
5207eeefd4aSBram Moolenaar 	    iptr->isn_arg.dfunc.cdf_idx = ufunc->uf_dfunc_idx;
5217eeefd4aSBram Moolenaar 	    iptr->isn_arg.dfunc.cdf_argcount = argcount;
5227eeefd4aSBram Moolenaar 	}
5238a7d6542SBram Moolenaar 	return call_dfunc(ufunc->uf_dfunc_idx, argcount, ectx);
5247eeefd4aSBram Moolenaar     }
5258a7d6542SBram Moolenaar 
5268a7d6542SBram Moolenaar     if (call_prepare(argcount, argvars, ectx) == FAIL)
5278a7d6542SBram Moolenaar 	return FAIL;
528a80faa89SBram Moolenaar     CLEAR_FIELD(funcexe);
5298a7d6542SBram Moolenaar     funcexe.evaluate = TRUE;
5308a7d6542SBram Moolenaar 
5318a7d6542SBram Moolenaar     // Call the user function.  Result goes in last position on the stack.
5328a7d6542SBram Moolenaar     // TODO: add selfdict if there is one
5338a7d6542SBram Moolenaar     error = call_user_func_check(ufunc, argcount, argvars,
5348a7d6542SBram Moolenaar 					     STACK_TV_BOT(-1), &funcexe, NULL);
5358a7d6542SBram Moolenaar 
5368a7d6542SBram Moolenaar     // Clear the arguments.
5378a7d6542SBram Moolenaar     for (idx = 0; idx < argcount; ++idx)
5388a7d6542SBram Moolenaar 	clear_tv(&argvars[idx]);
5398a7d6542SBram Moolenaar 
5408a7d6542SBram Moolenaar     if (error != FCERR_NONE)
5418a7d6542SBram Moolenaar     {
5428a7d6542SBram Moolenaar 	user_func_error(error, ufunc->uf_name);
5438a7d6542SBram Moolenaar 	return FAIL;
5448a7d6542SBram Moolenaar     }
5458a7d6542SBram Moolenaar     return OK;
5468a7d6542SBram Moolenaar }
5478a7d6542SBram Moolenaar 
5488a7d6542SBram Moolenaar /*
5498a7d6542SBram Moolenaar  * Execute a function by "name".
5508a7d6542SBram Moolenaar  * This can be a builtin function or a user function.
5517eeefd4aSBram Moolenaar  * "iptr" can be used to replace the instruction with a more efficient one.
5528a7d6542SBram Moolenaar  * Returns FAIL if not found without an error message.
5538a7d6542SBram Moolenaar  */
5548a7d6542SBram Moolenaar     static int
5557eeefd4aSBram Moolenaar call_by_name(char_u *name, int argcount, ectx_T *ectx, isn_T *iptr)
5568a7d6542SBram Moolenaar {
5578a7d6542SBram Moolenaar     ufunc_T *ufunc;
5588a7d6542SBram Moolenaar 
5598a7d6542SBram Moolenaar     if (builtin_function(name, -1))
5608a7d6542SBram Moolenaar     {
5618a7d6542SBram Moolenaar 	int func_idx = find_internal_func(name);
5628a7d6542SBram Moolenaar 
5638a7d6542SBram Moolenaar 	if (func_idx < 0)
5648a7d6542SBram Moolenaar 	    return FAIL;
565389df259SBram Moolenaar 	if (check_internal_func(func_idx, argcount) < 0)
5668a7d6542SBram Moolenaar 	    return FAIL;
5678a7d6542SBram Moolenaar 	return call_bfunc(func_idx, argcount, ectx);
5688a7d6542SBram Moolenaar     }
5698a7d6542SBram Moolenaar 
5704c17ad94SBram Moolenaar     ufunc = find_func(name, FALSE, NULL);
5718a7d6542SBram Moolenaar     if (ufunc != NULL)
5727eeefd4aSBram Moolenaar 	return call_ufunc(ufunc, argcount, ectx, iptr);
5738a7d6542SBram Moolenaar 
5748a7d6542SBram Moolenaar     return FAIL;
5758a7d6542SBram Moolenaar }
5768a7d6542SBram Moolenaar 
5778a7d6542SBram Moolenaar     static int
578a90afb9aSBram Moolenaar call_partial(typval_T *tv, int argcount_arg, ectx_T *ectx)
5798a7d6542SBram Moolenaar {
580a90afb9aSBram Moolenaar     int		argcount = argcount_arg;
581bd5da371SBram Moolenaar     char_u	*name = NULL;
5828a7d6542SBram Moolenaar     int		called_emsg_before = called_emsg;
5838a7d6542SBram Moolenaar 
5848a7d6542SBram Moolenaar     if (tv->v_type == VAR_PARTIAL)
5858a7d6542SBram Moolenaar     {
5868a7d6542SBram Moolenaar 	partial_T   *pt = tv->vval.v_partial;
587a90afb9aSBram Moolenaar 	int	    i;
588a90afb9aSBram Moolenaar 
589a90afb9aSBram Moolenaar 	if (pt->pt_argc > 0)
590a90afb9aSBram Moolenaar 	{
591a90afb9aSBram Moolenaar 	    // Make space for arguments from the partial, shift the "argcount"
592a90afb9aSBram Moolenaar 	    // arguments up.
593a90afb9aSBram Moolenaar 	    if (ga_grow(&ectx->ec_stack, pt->pt_argc) == FAIL)
594a90afb9aSBram Moolenaar 		return FAIL;
595a90afb9aSBram Moolenaar 	    for (i = 1; i <= argcount; ++i)
596a90afb9aSBram Moolenaar 		*STACK_TV_BOT(-i + pt->pt_argc) = *STACK_TV_BOT(-i);
597a90afb9aSBram Moolenaar 	    ectx->ec_stack.ga_len += pt->pt_argc;
598a90afb9aSBram Moolenaar 	    argcount += pt->pt_argc;
599a90afb9aSBram Moolenaar 
600a90afb9aSBram Moolenaar 	    // copy the arguments from the partial onto the stack
601a90afb9aSBram Moolenaar 	    for (i = 0; i < pt->pt_argc; ++i)
602a90afb9aSBram Moolenaar 		copy_tv(&pt->pt_argv[i], STACK_TV_BOT(-argcount + i));
603a90afb9aSBram Moolenaar 	}
6048a7d6542SBram Moolenaar 
6058a7d6542SBram Moolenaar 	if (pt->pt_func != NULL)
606f7779c63SBram Moolenaar 	{
607f7779c63SBram Moolenaar 	    int ret = call_ufunc(pt->pt_func, argcount, ectx, NULL);
608f7779c63SBram Moolenaar 
609f7779c63SBram Moolenaar 	    // closure may need the function context where it was defined
610f7779c63SBram Moolenaar 	    ectx->ec_outer_stack = pt->pt_ectx_stack;
611f7779c63SBram Moolenaar 	    ectx->ec_outer_frame = pt->pt_ectx_frame;
612f7779c63SBram Moolenaar 
613f7779c63SBram Moolenaar 	    return ret;
614f7779c63SBram Moolenaar 	}
6158a7d6542SBram Moolenaar 	name = pt->pt_name;
6168a7d6542SBram Moolenaar     }
617bd5da371SBram Moolenaar     else if (tv->v_type == VAR_FUNC)
6188a7d6542SBram Moolenaar 	name = tv->vval.v_string;
619bd5da371SBram Moolenaar     if (name == NULL || call_by_name(name, argcount, ectx, NULL) == FAIL)
6208a7d6542SBram Moolenaar     {
6218a7d6542SBram Moolenaar 	if (called_emsg == called_emsg_before)
622015f4267SBram Moolenaar 	    semsg(_(e_unknownfunc),
623015f4267SBram Moolenaar 				  name == NULL ? (char_u *)"[unknown]" : name);
6248a7d6542SBram Moolenaar 	return FAIL;
6258a7d6542SBram Moolenaar     }
6268a7d6542SBram Moolenaar     return OK;
6278a7d6542SBram Moolenaar }
6288a7d6542SBram Moolenaar 
6298a7d6542SBram Moolenaar /*
6300bbf722aSBram Moolenaar  * Store "tv" in variable "name".
6310bbf722aSBram Moolenaar  * This is for s: and g: variables.
6320bbf722aSBram Moolenaar  */
6330bbf722aSBram Moolenaar     static void
6340bbf722aSBram Moolenaar store_var(char_u *name, typval_T *tv)
6350bbf722aSBram Moolenaar {
6360bbf722aSBram Moolenaar     funccal_entry_T entry;
6370bbf722aSBram Moolenaar 
6380bbf722aSBram Moolenaar     save_funccal(&entry);
6395deeb3f1SBram Moolenaar     set_var_const(name, NULL, tv, FALSE, LET_NO_COMMAND);
6400bbf722aSBram Moolenaar     restore_funccal();
6410bbf722aSBram Moolenaar }
6420bbf722aSBram Moolenaar 
643d3aac291SBram Moolenaar 
6440bbf722aSBram Moolenaar /*
6458a7d6542SBram Moolenaar  * Execute a function by "name".
6468a7d6542SBram Moolenaar  * This can be a builtin function, user function or a funcref.
6477eeefd4aSBram Moolenaar  * "iptr" can be used to replace the instruction with a more efficient one.
6488a7d6542SBram Moolenaar  */
6498a7d6542SBram Moolenaar     static int
6507eeefd4aSBram Moolenaar call_eval_func(char_u *name, int argcount, ectx_T *ectx, isn_T *iptr)
6518a7d6542SBram Moolenaar {
6528a7d6542SBram Moolenaar     int		called_emsg_before = called_emsg;
6538a7d6542SBram Moolenaar 
6547eeefd4aSBram Moolenaar     if (call_by_name(name, argcount, ectx, iptr) == FAIL
6558a7d6542SBram Moolenaar 					  && called_emsg == called_emsg_before)
6568a7d6542SBram Moolenaar     {
6571df8b3fbSBram Moolenaar 	dictitem_T	*v;
6581df8b3fbSBram Moolenaar 
6591df8b3fbSBram Moolenaar 	v = find_var(name, NULL, FALSE);
6601df8b3fbSBram Moolenaar 	if (v == NULL)
6611df8b3fbSBram Moolenaar 	{
6621df8b3fbSBram Moolenaar 	    semsg(_(e_unknownfunc), name);
6638a7d6542SBram Moolenaar 	    return FAIL;
6648a7d6542SBram Moolenaar 	}
6651df8b3fbSBram Moolenaar 	if (v->di_tv.v_type != VAR_PARTIAL && v->di_tv.v_type != VAR_FUNC)
6661df8b3fbSBram Moolenaar 	{
6671df8b3fbSBram Moolenaar 	    semsg(_(e_unknownfunc), name);
6681df8b3fbSBram Moolenaar 	    return FAIL;
6691df8b3fbSBram Moolenaar 	}
6701df8b3fbSBram Moolenaar 	return call_partial(&v->di_tv, argcount, ectx);
6711df8b3fbSBram Moolenaar     }
6728a7d6542SBram Moolenaar     return OK;
6738a7d6542SBram Moolenaar }
6748a7d6542SBram Moolenaar 
6758a7d6542SBram Moolenaar /*
6768a7d6542SBram Moolenaar  * Call a "def" function from old Vim script.
6778a7d6542SBram Moolenaar  * Return OK or FAIL.
6788a7d6542SBram Moolenaar  */
6798a7d6542SBram Moolenaar     int
6808a7d6542SBram Moolenaar call_def_function(
6818a7d6542SBram Moolenaar     ufunc_T	*ufunc,
68223e03252SBram Moolenaar     int		argc_arg,	// nr of arguments
6838a7d6542SBram Moolenaar     typval_T	*argv,		// arguments
6846f5b6dfbSBram Moolenaar     partial_T	*partial,	// optional partial for context
6858a7d6542SBram Moolenaar     typval_T	*rettv)		// return value
6868a7d6542SBram Moolenaar {
6878a7d6542SBram Moolenaar     ectx_T	ectx;		// execution context
68823e03252SBram Moolenaar     int		argc = argc_arg;
689bf67ea1aSBram Moolenaar     int		initial_frame_idx;
6908a7d6542SBram Moolenaar     typval_T	*tv;
6918a7d6542SBram Moolenaar     int		idx;
6928a7d6542SBram Moolenaar     int		ret = FAIL;
693170fcfcfSBram Moolenaar     int		defcount = ufunc->uf_args.ga_len - argc;
694a26b9700SBram Moolenaar     int		save_sc_version = current_sctx.sc_version;
695270d0388SBram Moolenaar     int		breakcheck_count = 0;
69625e0f586SBram Moolenaar     int		called_emsg_before = called_emsg;
6978a7d6542SBram Moolenaar 
6988a7d6542SBram Moolenaar // Get pointer to item in the stack.
6998a7d6542SBram Moolenaar #define STACK_TV(idx) (((typval_T *)ectx.ec_stack.ga_data) + idx)
7008a7d6542SBram Moolenaar 
7018a7d6542SBram Moolenaar // Get pointer to item at the bottom of the stack, -1 is the bottom.
7028a7d6542SBram Moolenaar #undef STACK_TV_BOT
7038a7d6542SBram Moolenaar #define STACK_TV_BOT(idx) (((typval_T *)ectx.ec_stack.ga_data) + ectx.ec_stack.ga_len + idx)
7048a7d6542SBram Moolenaar 
7051378fbc4SBram Moolenaar // Get pointer to a local variable on the stack.  Negative for arguments.
706bf67ea1aSBram Moolenaar #define STACK_TV_VAR(idx) (((typval_T *)ectx.ec_stack.ga_data) + ectx.ec_frame_idx + STACK_FRAME_SIZE + idx)
7078a7d6542SBram Moolenaar 
708c8cd2b34SBram Moolenaar // Like STACK_TV_VAR but use the outer scope
709c8cd2b34SBram Moolenaar #define STACK_OUT_TV_VAR(idx) (((typval_T *)ectx.ec_outer_stack->ga_data) + ectx.ec_outer_frame + STACK_FRAME_SIZE + idx)
710c8cd2b34SBram Moolenaar 
7110cb5bcf5SBram Moolenaar     if (ufunc->uf_def_status == UF_NOT_COMPILED
7120cb5bcf5SBram Moolenaar 	    || (ufunc->uf_def_status == UF_TO_BE_COMPILED
713822ba247SBram Moolenaar 			  && compile_def_function(ufunc, FALSE, NULL) == FAIL))
71425e0f586SBram Moolenaar     {
71525e0f586SBram Moolenaar 	if (called_emsg == called_emsg_before)
71625e0f586SBram Moolenaar 	    semsg(_("E1091: Function is not compiled: %s"),
71725e0f586SBram Moolenaar 		    ufunc->uf_name_exp == NULL
71825e0f586SBram Moolenaar 					? ufunc->uf_name : ufunc->uf_name_exp);
719822ba247SBram Moolenaar 	return FAIL;
72025e0f586SBram Moolenaar     }
721822ba247SBram Moolenaar 
72209689a02SBram Moolenaar     {
723822ba247SBram Moolenaar 	// Check the function was really compiled.
72409689a02SBram Moolenaar 	dfunc_T	*dfunc = ((dfunc_T *)def_functions.ga_data)
72509689a02SBram Moolenaar 							 + ufunc->uf_dfunc_idx;
72609689a02SBram Moolenaar 	if (dfunc->df_instr == NULL)
72709689a02SBram Moolenaar 	    return FAIL;
72809689a02SBram Moolenaar     }
7298a7d6542SBram Moolenaar 
7303b6a6eb7SBram Moolenaar     CLEAR_FIELD(ectx);
7313b6a6eb7SBram Moolenaar     ectx.ec_dfunc_idx = ufunc->uf_dfunc_idx;
7323b6a6eb7SBram Moolenaar     ga_init2(&ectx.ec_stack, sizeof(typval_T), 500);
7333b6a6eb7SBram Moolenaar     if (ga_grow(&ectx.ec_stack, 20) == FAIL)
7343b6a6eb7SBram Moolenaar 	return FAIL;
7358a7d6542SBram Moolenaar     ga_init2(&ectx.ec_trystack, sizeof(trycmd_T), 10);
7368a7d6542SBram Moolenaar 
7378a7d6542SBram Moolenaar     // Put arguments on the stack.
7388a7d6542SBram Moolenaar     for (idx = 0; idx < argc; ++idx)
7398a7d6542SBram Moolenaar     {
740*65b9545fSBram Moolenaar 	if (ufunc->uf_arg_types != NULL && idx < ufunc->uf_args.ga_len
741*65b9545fSBram Moolenaar 		&& check_argtype(ufunc->uf_arg_types[idx], &argv[idx]) == FAIL)
742*65b9545fSBram Moolenaar 	    goto failed_early;
7438a7d6542SBram Moolenaar 	copy_tv(&argv[idx], STACK_TV_BOT(0));
7448a7d6542SBram Moolenaar 	++ectx.ec_stack.ga_len;
7458a7d6542SBram Moolenaar     }
74623e03252SBram Moolenaar 
74723e03252SBram Moolenaar     // Turn varargs into a list.  Empty list if no args.
74823e03252SBram Moolenaar     if (ufunc->uf_va_name != NULL)
74923e03252SBram Moolenaar     {
75023e03252SBram Moolenaar 	int vararg_count = argc - ufunc->uf_args.ga_len;
75123e03252SBram Moolenaar 
75223e03252SBram Moolenaar 	if (vararg_count < 0)
75323e03252SBram Moolenaar 	    vararg_count = 0;
75423e03252SBram Moolenaar 	else
75523e03252SBram Moolenaar 	    argc -= vararg_count;
75623e03252SBram Moolenaar 	if (exe_newlist(vararg_count, &ectx) == FAIL)
7571a2f4bf6SBram Moolenaar 	    goto failed_early;
75823e03252SBram Moolenaar 	if (defcount > 0)
75923e03252SBram Moolenaar 	    // Move varargs list to below missing default arguments.
76023e03252SBram Moolenaar 	    *STACK_TV_BOT(defcount- 1) = *STACK_TV_BOT(-1);
76123e03252SBram Moolenaar 	--ectx.ec_stack.ga_len;
76223e03252SBram Moolenaar     }
76323e03252SBram Moolenaar 
764170fcfcfSBram Moolenaar     // Make space for omitted arguments, will store default value below.
76523e03252SBram Moolenaar     // Any varargs list goes after them.
766170fcfcfSBram Moolenaar     if (defcount > 0)
767170fcfcfSBram Moolenaar 	for (idx = 0; idx < defcount; ++idx)
768170fcfcfSBram Moolenaar 	{
769170fcfcfSBram Moolenaar 	    STACK_TV_BOT(0)->v_type = VAR_UNKNOWN;
770170fcfcfSBram Moolenaar 	    ++ectx.ec_stack.ga_len;
771170fcfcfSBram Moolenaar 	}
77223e03252SBram Moolenaar     if (ufunc->uf_va_name != NULL)
77323e03252SBram Moolenaar 	    ++ectx.ec_stack.ga_len;
7748a7d6542SBram Moolenaar 
7758a7d6542SBram Moolenaar     // Frame pointer points to just after arguments.
776bf67ea1aSBram Moolenaar     ectx.ec_frame_idx = ectx.ec_stack.ga_len;
777bf67ea1aSBram Moolenaar     initial_frame_idx = ectx.ec_frame_idx;
7788a7d6542SBram Moolenaar 
7796f5b6dfbSBram Moolenaar     if (partial != NULL)
7806f5b6dfbSBram Moolenaar     {
78108f7a41bSBram Moolenaar 	if (partial->pt_ectx_stack == NULL && current_ectx != NULL)
78208f7a41bSBram Moolenaar 	{
78308f7a41bSBram Moolenaar 	    // TODO: is this always the right way?
78408f7a41bSBram Moolenaar 	    ectx.ec_outer_stack = &current_ectx->ec_stack;
78508f7a41bSBram Moolenaar 	    ectx.ec_outer_frame = current_ectx->ec_frame_idx;
78608f7a41bSBram Moolenaar 	}
78708f7a41bSBram Moolenaar 	else
78808f7a41bSBram Moolenaar 	{
7896f5b6dfbSBram Moolenaar 	    ectx.ec_outer_stack = partial->pt_ectx_stack;
7906f5b6dfbSBram Moolenaar 	    ectx.ec_outer_frame = partial->pt_ectx_frame;
7916f5b6dfbSBram Moolenaar 	}
79208f7a41bSBram Moolenaar     }
7936f5b6dfbSBram Moolenaar 
7948a7d6542SBram Moolenaar     // dummy frame entries
7958a7d6542SBram Moolenaar     for (idx = 0; idx < STACK_FRAME_SIZE; ++idx)
7968a7d6542SBram Moolenaar     {
7978a7d6542SBram Moolenaar 	STACK_TV(ectx.ec_stack.ga_len)->v_type = VAR_UNKNOWN;
7988a7d6542SBram Moolenaar 	++ectx.ec_stack.ga_len;
7998a7d6542SBram Moolenaar     }
8008a7d6542SBram Moolenaar 
801bd5da371SBram Moolenaar     {
802bf67ea1aSBram Moolenaar 	// Reserve space for local variables and closure references.
803bd5da371SBram Moolenaar 	dfunc_T	*dfunc = ((dfunc_T *)def_functions.ga_data)
804bd5da371SBram Moolenaar 							 + ufunc->uf_dfunc_idx;
805bf67ea1aSBram Moolenaar 	int	count = dfunc->df_varcount + dfunc->df_closure_count;
806bd5da371SBram Moolenaar 
807bf67ea1aSBram Moolenaar 	for (idx = 0; idx < count; ++idx)
8088a7d6542SBram Moolenaar 	    STACK_TV_VAR(idx)->v_type = VAR_UNKNOWN;
809bf67ea1aSBram Moolenaar 	ectx.ec_stack.ga_len += count;
8108a7d6542SBram Moolenaar 
8118a7d6542SBram Moolenaar 	ectx.ec_instr = dfunc->df_instr;
812bd5da371SBram Moolenaar     }
813170fcfcfSBram Moolenaar 
814a26b9700SBram Moolenaar     // Commands behave like vim9script.
815a26b9700SBram Moolenaar     current_sctx.sc_version = SCRIPT_VERSION_VIM9;
816a26b9700SBram Moolenaar 
817170fcfcfSBram Moolenaar     // Decide where to start execution, handles optional arguments.
818170fcfcfSBram Moolenaar     init_instr_idx(ufunc, argc, &ectx);
819170fcfcfSBram Moolenaar 
8208a7d6542SBram Moolenaar     for (;;)
8218a7d6542SBram Moolenaar     {
8228a7d6542SBram Moolenaar 	isn_T	    *iptr;
82320431c9dSBram Moolenaar 
824270d0388SBram Moolenaar 	if (++breakcheck_count >= 100)
825270d0388SBram Moolenaar 	{
826270d0388SBram Moolenaar 	    line_breakcheck();
827270d0388SBram Moolenaar 	    breakcheck_count = 0;
828270d0388SBram Moolenaar 	}
82920431c9dSBram Moolenaar 	if (got_int)
83020431c9dSBram Moolenaar 	{
83120431c9dSBram Moolenaar 	    // Turn CTRL-C into an exception.
83220431c9dSBram Moolenaar 	    got_int = FALSE;
83397acfc78SBram Moolenaar 	    if (throw_exception("Vim:Interrupt", ET_INTERRUPT, NULL) == FAIL)
83420431c9dSBram Moolenaar 		goto failed;
83520431c9dSBram Moolenaar 	    did_throw = TRUE;
83620431c9dSBram Moolenaar 	}
8378a7d6542SBram Moolenaar 
838a26b9700SBram Moolenaar 	if (did_emsg && msg_list != NULL && *msg_list != NULL)
839a26b9700SBram Moolenaar 	{
840a26b9700SBram Moolenaar 	    // Turn an error message into an exception.
841a26b9700SBram Moolenaar 	    did_emsg = FALSE;
842a26b9700SBram Moolenaar 	    if (throw_exception(*msg_list, ET_ERROR, NULL) == FAIL)
843a26b9700SBram Moolenaar 		goto failed;
844a26b9700SBram Moolenaar 	    did_throw = TRUE;
845a26b9700SBram Moolenaar 	    *msg_list = NULL;
846a26b9700SBram Moolenaar 	}
847a26b9700SBram Moolenaar 
8488a7d6542SBram Moolenaar 	if (did_throw && !ectx.ec_in_catch)
8498a7d6542SBram Moolenaar 	{
8508a7d6542SBram Moolenaar 	    garray_T	*trystack = &ectx.ec_trystack;
85120431c9dSBram Moolenaar 	    trycmd_T    *trycmd = NULL;
8528a7d6542SBram Moolenaar 
8538a7d6542SBram Moolenaar 	    // An exception jumps to the first catch, finally, or returns from
8548a7d6542SBram Moolenaar 	    // the current function.
8558a7d6542SBram Moolenaar 	    if (trystack->ga_len > 0)
8568a7d6542SBram Moolenaar 		trycmd = ((trycmd_T *)trystack->ga_data) + trystack->ga_len - 1;
857bf67ea1aSBram Moolenaar 	    if (trycmd != NULL && trycmd->tcd_frame_idx == ectx.ec_frame_idx)
8588a7d6542SBram Moolenaar 	    {
8598a7d6542SBram Moolenaar 		// jump to ":catch" or ":finally"
8608a7d6542SBram Moolenaar 		ectx.ec_in_catch = TRUE;
8618a7d6542SBram Moolenaar 		ectx.ec_iidx = trycmd->tcd_catch_idx;
8628a7d6542SBram Moolenaar 	    }
8638a7d6542SBram Moolenaar 	    else
8648a7d6542SBram Moolenaar 	    {
8658a7d6542SBram Moolenaar 		// not inside try or need to return from current functions.
866bf67ea1aSBram Moolenaar 		if (ectx.ec_frame_idx == initial_frame_idx)
8678a7d6542SBram Moolenaar 		{
8688a7d6542SBram Moolenaar 		    // At the toplevel we are done.  Push a dummy return value.
869270d0388SBram Moolenaar 		    if (GA_GROW(&ectx.ec_stack, 1) == FAIL)
8708a7d6542SBram Moolenaar 			goto failed;
8718a7d6542SBram Moolenaar 		    tv = STACK_TV_BOT(0);
8728a7d6542SBram Moolenaar 		    tv->v_type = VAR_NUMBER;
8738a7d6542SBram Moolenaar 		    tv->vval.v_number = 0;
8748a7d6542SBram Moolenaar 		    ++ectx.ec_stack.ga_len;
875257cc5eeSBram Moolenaar 		    need_rethrow = TRUE;
876bf67ea1aSBram Moolenaar 		    if (handle_closure_in_use(&ectx, FALSE) == FAIL)
877bf67ea1aSBram Moolenaar 			goto failed;
8788a7d6542SBram Moolenaar 		    goto done;
8798a7d6542SBram Moolenaar 		}
8808a7d6542SBram Moolenaar 
881bf67ea1aSBram Moolenaar 		if (func_return(&ectx) == FAIL)
882bf67ea1aSBram Moolenaar 		    goto failed;
8838a7d6542SBram Moolenaar 	    }
8848a7d6542SBram Moolenaar 	    continue;
8858a7d6542SBram Moolenaar 	}
8868a7d6542SBram Moolenaar 
8878a7d6542SBram Moolenaar 	iptr = &ectx.ec_instr[ectx.ec_iidx++];
8888a7d6542SBram Moolenaar 	switch (iptr->isn_type)
8898a7d6542SBram Moolenaar 	{
8908a7d6542SBram Moolenaar 	    // execute Ex command line
8918a7d6542SBram Moolenaar 	    case ISN_EXEC:
8926378c4feSBram Moolenaar 		SOURCING_LNUM = iptr->isn_lnum;
8938a7d6542SBram Moolenaar 		do_cmdline_cmd(iptr->isn_arg.string);
8948a7d6542SBram Moolenaar 		break;
8958a7d6542SBram Moolenaar 
896cfe435d7SBram Moolenaar 	    // execute Ex command from pieces on the stack
897cfe435d7SBram Moolenaar 	    case ISN_EXECCONCAT:
898cfe435d7SBram Moolenaar 		{
899cfe435d7SBram Moolenaar 		    int	    count = iptr->isn_arg.number;
9007f6f56f4SBram Moolenaar 		    size_t  len = 0;
901cfe435d7SBram Moolenaar 		    int	    pass;
902cfe435d7SBram Moolenaar 		    int	    i;
903cfe435d7SBram Moolenaar 		    char_u  *cmd = NULL;
904cfe435d7SBram Moolenaar 		    char_u  *str;
905cfe435d7SBram Moolenaar 
906cfe435d7SBram Moolenaar 		    for (pass = 1; pass <= 2; ++pass)
907cfe435d7SBram Moolenaar 		    {
908cfe435d7SBram Moolenaar 			for (i = 0; i < count; ++i)
909cfe435d7SBram Moolenaar 			{
910cfe435d7SBram Moolenaar 			    tv = STACK_TV_BOT(i - count);
911cfe435d7SBram Moolenaar 			    str = tv->vval.v_string;
912cfe435d7SBram Moolenaar 			    if (str != NULL && *str != NUL)
913cfe435d7SBram Moolenaar 			    {
914cfe435d7SBram Moolenaar 				if (pass == 2)
915cfe435d7SBram Moolenaar 				    STRCPY(cmd + len, str);
916cfe435d7SBram Moolenaar 				len += STRLEN(str);
917cfe435d7SBram Moolenaar 			    }
918cfe435d7SBram Moolenaar 			    if (pass == 2)
919cfe435d7SBram Moolenaar 				clear_tv(tv);
920cfe435d7SBram Moolenaar 			}
921cfe435d7SBram Moolenaar 			if (pass == 1)
922cfe435d7SBram Moolenaar 			{
923cfe435d7SBram Moolenaar 			    cmd = alloc(len + 1);
924cfe435d7SBram Moolenaar 			    if (cmd == NULL)
925cfe435d7SBram Moolenaar 				goto failed;
926cfe435d7SBram Moolenaar 			    len = 0;
927cfe435d7SBram Moolenaar 			}
928cfe435d7SBram Moolenaar 		    }
929cfe435d7SBram Moolenaar 
9306378c4feSBram Moolenaar 		    SOURCING_LNUM = iptr->isn_lnum;
931cfe435d7SBram Moolenaar 		    do_cmdline_cmd(cmd);
932cfe435d7SBram Moolenaar 		    vim_free(cmd);
933cfe435d7SBram Moolenaar 		}
934cfe435d7SBram Moolenaar 		break;
935cfe435d7SBram Moolenaar 
9368a7d6542SBram Moolenaar 	    // execute :echo {string} ...
9378a7d6542SBram Moolenaar 	    case ISN_ECHO:
9388a7d6542SBram Moolenaar 		{
9398a7d6542SBram Moolenaar 		    int count = iptr->isn_arg.echo.echo_count;
9408a7d6542SBram Moolenaar 		    int	atstart = TRUE;
9418a7d6542SBram Moolenaar 		    int needclr = TRUE;
9428a7d6542SBram Moolenaar 
9438a7d6542SBram Moolenaar 		    for (idx = 0; idx < count; ++idx)
9448a7d6542SBram Moolenaar 		    {
9458a7d6542SBram Moolenaar 			tv = STACK_TV_BOT(idx - count);
9468a7d6542SBram Moolenaar 			echo_one(tv, iptr->isn_arg.echo.echo_with_white,
9478a7d6542SBram Moolenaar 							   &atstart, &needclr);
9488a7d6542SBram Moolenaar 			clear_tv(tv);
9498a7d6542SBram Moolenaar 		    }
950e0807ea4SBram Moolenaar 		    if (needclr)
951e0807ea4SBram Moolenaar 			msg_clr_eos();
9528a7d6542SBram Moolenaar 		    ectx.ec_stack.ga_len -= count;
9538a7d6542SBram Moolenaar 		}
9548a7d6542SBram Moolenaar 		break;
9558a7d6542SBram Moolenaar 
956f93c7feaSBram Moolenaar 	    // :execute {string} ...
957f93c7feaSBram Moolenaar 	    // :echomsg {string} ...
958f93c7feaSBram Moolenaar 	    // :echoerr {string} ...
959ad39c094SBram Moolenaar 	    case ISN_EXECUTE:
960f93c7feaSBram Moolenaar 	    case ISN_ECHOMSG:
961f93c7feaSBram Moolenaar 	    case ISN_ECHOERR:
962ad39c094SBram Moolenaar 		{
963ad39c094SBram Moolenaar 		    int		count = iptr->isn_arg.number;
964ad39c094SBram Moolenaar 		    garray_T	ga;
965ad39c094SBram Moolenaar 		    char_u	buf[NUMBUFLEN];
966ad39c094SBram Moolenaar 		    char_u	*p;
967ad39c094SBram Moolenaar 		    int		len;
968ad39c094SBram Moolenaar 		    int		failed = FALSE;
969ad39c094SBram Moolenaar 
970ad39c094SBram Moolenaar 		    ga_init2(&ga, 1, 80);
971ad39c094SBram Moolenaar 		    for (idx = 0; idx < count; ++idx)
972ad39c094SBram Moolenaar 		    {
973ad39c094SBram Moolenaar 			tv = STACK_TV_BOT(idx - count);
974ad39c094SBram Moolenaar 			if (tv->v_type == VAR_CHANNEL || tv->v_type == VAR_JOB)
975ad39c094SBram Moolenaar 			{
976ad39c094SBram Moolenaar 			    emsg(_(e_inval_string));
977ad39c094SBram Moolenaar 			    break;
978ad39c094SBram Moolenaar 			}
979ad39c094SBram Moolenaar 			else
980ad39c094SBram Moolenaar 			    p = tv_get_string_buf(tv, buf);
981ad39c094SBram Moolenaar 
982ad39c094SBram Moolenaar 			len = (int)STRLEN(p);
983ad39c094SBram Moolenaar 			if (ga_grow(&ga, len + 2) == FAIL)
984ad39c094SBram Moolenaar 			    failed = TRUE;
985ad39c094SBram Moolenaar 			else
986ad39c094SBram Moolenaar 			{
987ad39c094SBram Moolenaar 			    if (ga.ga_len > 0)
988ad39c094SBram Moolenaar 				((char_u *)(ga.ga_data))[ga.ga_len++] = ' ';
989ad39c094SBram Moolenaar 			    STRCPY((char_u *)(ga.ga_data) + ga.ga_len, p);
990ad39c094SBram Moolenaar 			    ga.ga_len += len;
991ad39c094SBram Moolenaar 			}
992ad39c094SBram Moolenaar 			clear_tv(tv);
993ad39c094SBram Moolenaar 		    }
994ad39c094SBram Moolenaar 		    ectx.ec_stack.ga_len -= count;
995ad39c094SBram Moolenaar 
996ad39c094SBram Moolenaar 		    if (!failed && ga.ga_data != NULL)
997f93c7feaSBram Moolenaar 		    {
998f93c7feaSBram Moolenaar 			if (iptr->isn_type == ISN_EXECUTE)
999ad39c094SBram Moolenaar 			    do_cmdline_cmd((char_u *)ga.ga_data);
1000f93c7feaSBram Moolenaar 			else
1001f93c7feaSBram Moolenaar 			{
1002f93c7feaSBram Moolenaar 			    msg_sb_eol();
1003f93c7feaSBram Moolenaar 			    if (iptr->isn_type == ISN_ECHOMSG)
1004f93c7feaSBram Moolenaar 			    {
1005f93c7feaSBram Moolenaar 				msg_attr(ga.ga_data, echo_attr);
1006f93c7feaSBram Moolenaar 				out_flush();
1007f93c7feaSBram Moolenaar 			    }
1008f93c7feaSBram Moolenaar 			    else
1009f93c7feaSBram Moolenaar 			    {
1010f93c7feaSBram Moolenaar 				SOURCING_LNUM = iptr->isn_lnum;
1011f93c7feaSBram Moolenaar 				emsg(ga.ga_data);
1012f93c7feaSBram Moolenaar 			    }
1013f93c7feaSBram Moolenaar 			}
1014f93c7feaSBram Moolenaar 		    }
1015ad39c094SBram Moolenaar 		    ga_clear(&ga);
1016ad39c094SBram Moolenaar 		}
1017ad39c094SBram Moolenaar 		break;
1018ad39c094SBram Moolenaar 
10198a7d6542SBram Moolenaar 	    // load local variable or argument
10208a7d6542SBram Moolenaar 	    case ISN_LOAD:
1021270d0388SBram Moolenaar 		if (GA_GROW(&ectx.ec_stack, 1) == FAIL)
10228a7d6542SBram Moolenaar 		    goto failed;
10238a7d6542SBram Moolenaar 		copy_tv(STACK_TV_VAR(iptr->isn_arg.number), STACK_TV_BOT(0));
10248a7d6542SBram Moolenaar 		++ectx.ec_stack.ga_len;
10258a7d6542SBram Moolenaar 		break;
10268a7d6542SBram Moolenaar 
1027c8cd2b34SBram Moolenaar 	    // load variable or argument from outer scope
1028c8cd2b34SBram Moolenaar 	    case ISN_LOADOUTER:
1029270d0388SBram Moolenaar 		if (GA_GROW(&ectx.ec_stack, 1) == FAIL)
1030c8cd2b34SBram Moolenaar 		    goto failed;
1031c8cd2b34SBram Moolenaar 		copy_tv(STACK_OUT_TV_VAR(iptr->isn_arg.number),
1032c8cd2b34SBram Moolenaar 							      STACK_TV_BOT(0));
1033c8cd2b34SBram Moolenaar 		++ectx.ec_stack.ga_len;
1034c8cd2b34SBram Moolenaar 		break;
1035c8cd2b34SBram Moolenaar 
10368a7d6542SBram Moolenaar 	    // load v: variable
10378a7d6542SBram Moolenaar 	    case ISN_LOADV:
1038270d0388SBram Moolenaar 		if (GA_GROW(&ectx.ec_stack, 1) == FAIL)
10398a7d6542SBram Moolenaar 		    goto failed;
10408a7d6542SBram Moolenaar 		copy_tv(get_vim_var_tv(iptr->isn_arg.number), STACK_TV_BOT(0));
10418a7d6542SBram Moolenaar 		++ectx.ec_stack.ga_len;
10428a7d6542SBram Moolenaar 		break;
10438a7d6542SBram Moolenaar 
1044b283a8a6SBram Moolenaar 	    // load s: variable in Vim9 script
10458a7d6542SBram Moolenaar 	    case ISN_LOADSCRIPT:
10468a7d6542SBram Moolenaar 		{
10478a7d6542SBram Moolenaar 		    scriptitem_T *si =
104821b9e977SBram Moolenaar 				  SCRIPT_ITEM(iptr->isn_arg.script.script_sid);
10498a7d6542SBram Moolenaar 		    svar_T	 *sv;
10508a7d6542SBram Moolenaar 
10518a7d6542SBram Moolenaar 		    sv = ((svar_T *)si->sn_var_vals.ga_data)
10528a7d6542SBram Moolenaar 					     + iptr->isn_arg.script.script_idx;
1053270d0388SBram Moolenaar 		    if (GA_GROW(&ectx.ec_stack, 1) == FAIL)
10548a7d6542SBram Moolenaar 			goto failed;
10558a7d6542SBram Moolenaar 		    copy_tv(sv->sv_tv, STACK_TV_BOT(0));
10568a7d6542SBram Moolenaar 		    ++ectx.ec_stack.ga_len;
10578a7d6542SBram Moolenaar 		}
10588a7d6542SBram Moolenaar 		break;
10598a7d6542SBram Moolenaar 
10608a7d6542SBram Moolenaar 	    // load s: variable in old script
10618a7d6542SBram Moolenaar 	    case ISN_LOADS:
10628a7d6542SBram Moolenaar 		{
1063b283a8a6SBram Moolenaar 		    hashtab_T	*ht = &SCRIPT_VARS(
1064b283a8a6SBram Moolenaar 					       iptr->isn_arg.loadstore.ls_sid);
1065b283a8a6SBram Moolenaar 		    char_u	*name = iptr->isn_arg.loadstore.ls_name;
10668a7d6542SBram Moolenaar 		    dictitem_T	*di = find_var_in_ht(ht, 0, name, TRUE);
10670bbf722aSBram Moolenaar 
10688a7d6542SBram Moolenaar 		    if (di == NULL)
10698a7d6542SBram Moolenaar 		    {
1070b283a8a6SBram Moolenaar 			semsg(_(e_undefvar), name);
1071f0b9f43cSBram Moolenaar 			goto on_error;
10728a7d6542SBram Moolenaar 		    }
10738a7d6542SBram Moolenaar 		    else
10748a7d6542SBram Moolenaar 		    {
1075270d0388SBram Moolenaar 			if (GA_GROW(&ectx.ec_stack, 1) == FAIL)
10768a7d6542SBram Moolenaar 			    goto failed;
10778a7d6542SBram Moolenaar 			copy_tv(&di->di_tv, STACK_TV_BOT(0));
10788a7d6542SBram Moolenaar 			++ectx.ec_stack.ga_len;
10798a7d6542SBram Moolenaar 		    }
10808a7d6542SBram Moolenaar 		}
10818a7d6542SBram Moolenaar 		break;
10828a7d6542SBram Moolenaar 
1083d3aac291SBram Moolenaar 	    // load g:/b:/w:/t: variable
10848a7d6542SBram Moolenaar 	    case ISN_LOADG:
1085d3aac291SBram Moolenaar 	    case ISN_LOADB:
1086d3aac291SBram Moolenaar 	    case ISN_LOADW:
1087d3aac291SBram Moolenaar 	    case ISN_LOADT:
10888a7d6542SBram Moolenaar 		{
1089d3aac291SBram Moolenaar 		    dictitem_T *di = NULL;
1090d3aac291SBram Moolenaar 		    hashtab_T *ht = NULL;
1091d3aac291SBram Moolenaar 		    char namespace;
1092d3aac291SBram Moolenaar 		    switch (iptr->isn_type)
1093d3aac291SBram Moolenaar 		    {
1094d3aac291SBram Moolenaar 			case ISN_LOADG:
1095d3aac291SBram Moolenaar 			    ht = get_globvar_ht();
1096d3aac291SBram Moolenaar 			    namespace = 'g';
1097d3aac291SBram Moolenaar 			    break;
1098d3aac291SBram Moolenaar 			case ISN_LOADB:
1099d3aac291SBram Moolenaar 			    ht = &curbuf->b_vars->dv_hashtab;
1100d3aac291SBram Moolenaar 			    namespace = 'b';
1101d3aac291SBram Moolenaar 			    break;
1102d3aac291SBram Moolenaar 			case ISN_LOADW:
1103d3aac291SBram Moolenaar 			    ht = &curwin->w_vars->dv_hashtab;
1104d3aac291SBram Moolenaar 			    namespace = 'w';
1105d3aac291SBram Moolenaar 			    break;
1106d3aac291SBram Moolenaar 			case ISN_LOADT:
1107d3aac291SBram Moolenaar 			    ht = &curtab->tp_vars->dv_hashtab;
1108d3aac291SBram Moolenaar 			    namespace = 't';
1109d3aac291SBram Moolenaar 			    break;
1110d3aac291SBram Moolenaar 			default:  // Cannot reach here
1111d3aac291SBram Moolenaar 			    goto failed;
1112d3aac291SBram Moolenaar 		    }
1113d3aac291SBram Moolenaar 		    di = find_var_in_ht(ht, 0, iptr->isn_arg.string, TRUE);
11140bbf722aSBram Moolenaar 
11158a7d6542SBram Moolenaar 		    if (di == NULL)
11168a7d6542SBram Moolenaar 		    {
1117d3aac291SBram Moolenaar 			semsg(_("E121: Undefined variable: %c:%s"),
1118d3aac291SBram Moolenaar 					     namespace, iptr->isn_arg.string);
1119f0b9f43cSBram Moolenaar 			goto on_error;
11208a7d6542SBram Moolenaar 		    }
11218a7d6542SBram Moolenaar 		    else
11228a7d6542SBram Moolenaar 		    {
1123270d0388SBram Moolenaar 			if (GA_GROW(&ectx.ec_stack, 1) == FAIL)
11248a7d6542SBram Moolenaar 			    goto failed;
11258a7d6542SBram Moolenaar 			copy_tv(&di->di_tv, STACK_TV_BOT(0));
11268a7d6542SBram Moolenaar 			++ectx.ec_stack.ga_len;
11278a7d6542SBram Moolenaar 		    }
11288a7d6542SBram Moolenaar 		}
11298a7d6542SBram Moolenaar 		break;
11308a7d6542SBram Moolenaar 
11318a7d6542SBram Moolenaar 	    // load &option
11328a7d6542SBram Moolenaar 	    case ISN_LOADOPT:
11338a7d6542SBram Moolenaar 		{
11348a7d6542SBram Moolenaar 		    typval_T	optval;
11358a7d6542SBram Moolenaar 		    char_u	*name = iptr->isn_arg.string;
11368a7d6542SBram Moolenaar 
1137a8c17704SBram Moolenaar 		    // This is not expected to fail, name is checked during
1138a8c17704SBram Moolenaar 		    // compilation: don't set SOURCING_LNUM.
1139270d0388SBram Moolenaar 		    if (GA_GROW(&ectx.ec_stack, 1) == FAIL)
11408a7d6542SBram Moolenaar 			goto failed;
11419a78e6dfSBram Moolenaar 		    if (eval_option(&name, &optval, TRUE) == FAIL)
114258ceca5cSBram Moolenaar 			goto failed;
11438a7d6542SBram Moolenaar 		    *STACK_TV_BOT(0) = optval;
11448a7d6542SBram Moolenaar 		    ++ectx.ec_stack.ga_len;
11458a7d6542SBram Moolenaar 		}
11468a7d6542SBram Moolenaar 		break;
11478a7d6542SBram Moolenaar 
11488a7d6542SBram Moolenaar 	    // load $ENV
11498a7d6542SBram Moolenaar 	    case ISN_LOADENV:
11508a7d6542SBram Moolenaar 		{
11518a7d6542SBram Moolenaar 		    typval_T	optval;
11528a7d6542SBram Moolenaar 		    char_u	*name = iptr->isn_arg.string;
11538a7d6542SBram Moolenaar 
1154270d0388SBram Moolenaar 		    if (GA_GROW(&ectx.ec_stack, 1) == FAIL)
11558a7d6542SBram Moolenaar 			goto failed;
11560bbf722aSBram Moolenaar 		    // name is always valid, checked when compiling
11579a78e6dfSBram Moolenaar 		    (void)eval_env_var(&name, &optval, TRUE);
11588a7d6542SBram Moolenaar 		    *STACK_TV_BOT(0) = optval;
11598a7d6542SBram Moolenaar 		    ++ectx.ec_stack.ga_len;
11608a7d6542SBram Moolenaar 		}
11618a7d6542SBram Moolenaar 		break;
11628a7d6542SBram Moolenaar 
11638a7d6542SBram Moolenaar 	    // load @register
11648a7d6542SBram Moolenaar 	    case ISN_LOADREG:
1165270d0388SBram Moolenaar 		if (GA_GROW(&ectx.ec_stack, 1) == FAIL)
11668a7d6542SBram Moolenaar 		    goto failed;
11678a7d6542SBram Moolenaar 		tv = STACK_TV_BOT(0);
11688a7d6542SBram Moolenaar 		tv->v_type = VAR_STRING;
11698a7d6542SBram Moolenaar 		tv->vval.v_string = get_reg_contents(
11708a7d6542SBram Moolenaar 					  iptr->isn_arg.number, GREG_EXPR_SRC);
11718a7d6542SBram Moolenaar 		++ectx.ec_stack.ga_len;
11728a7d6542SBram Moolenaar 		break;
11738a7d6542SBram Moolenaar 
11748a7d6542SBram Moolenaar 	    // store local variable
11758a7d6542SBram Moolenaar 	    case ISN_STORE:
11768a7d6542SBram Moolenaar 		--ectx.ec_stack.ga_len;
11778a7d6542SBram Moolenaar 		tv = STACK_TV_VAR(iptr->isn_arg.number);
11788a7d6542SBram Moolenaar 		clear_tv(tv);
11798a7d6542SBram Moolenaar 		*tv = *STACK_TV_BOT(0);
11808a7d6542SBram Moolenaar 		break;
11818a7d6542SBram Moolenaar 
1182b68b346eSBram Moolenaar 	    // store variable or argument in outer scope
1183b68b346eSBram Moolenaar 	    case ISN_STOREOUTER:
1184b68b346eSBram Moolenaar 		--ectx.ec_stack.ga_len;
1185b68b346eSBram Moolenaar 		tv = STACK_OUT_TV_VAR(iptr->isn_arg.number);
1186b68b346eSBram Moolenaar 		clear_tv(tv);
1187b68b346eSBram Moolenaar 		*tv = *STACK_TV_BOT(0);
1188b68b346eSBram Moolenaar 		break;
1189b68b346eSBram Moolenaar 
1190b283a8a6SBram Moolenaar 	    // store s: variable in old script
1191b283a8a6SBram Moolenaar 	    case ISN_STORES:
1192b283a8a6SBram Moolenaar 		{
1193b283a8a6SBram Moolenaar 		    hashtab_T	*ht = &SCRIPT_VARS(
1194b283a8a6SBram Moolenaar 					       iptr->isn_arg.loadstore.ls_sid);
1195b283a8a6SBram Moolenaar 		    char_u	*name = iptr->isn_arg.loadstore.ls_name;
11960bbf722aSBram Moolenaar 		    dictitem_T	*di = find_var_in_ht(ht, 0, name + 2, TRUE);
1197b283a8a6SBram Moolenaar 
1198b283a8a6SBram Moolenaar 		    --ectx.ec_stack.ga_len;
11990bbf722aSBram Moolenaar 		    if (di == NULL)
12005deeb3f1SBram Moolenaar 			store_var(name, STACK_TV_BOT(0));
12010bbf722aSBram Moolenaar 		    else
12020bbf722aSBram Moolenaar 		    {
1203b283a8a6SBram Moolenaar 			clear_tv(&di->di_tv);
1204b283a8a6SBram Moolenaar 			di->di_tv = *STACK_TV_BOT(0);
1205b283a8a6SBram Moolenaar 		    }
12060bbf722aSBram Moolenaar 		}
1207b283a8a6SBram Moolenaar 		break;
1208b283a8a6SBram Moolenaar 
1209b283a8a6SBram Moolenaar 	    // store script-local variable in Vim9 script
12108a7d6542SBram Moolenaar 	    case ISN_STORESCRIPT:
12118a7d6542SBram Moolenaar 		{
121221b9e977SBram Moolenaar 		    scriptitem_T *si = SCRIPT_ITEM(
12138a7d6542SBram Moolenaar 					      iptr->isn_arg.script.script_sid);
12148a7d6542SBram Moolenaar 		    svar_T	 *sv = ((svar_T *)si->sn_var_vals.ga_data)
12158a7d6542SBram Moolenaar 					     + iptr->isn_arg.script.script_idx;
12168a7d6542SBram Moolenaar 
12178a7d6542SBram Moolenaar 		    --ectx.ec_stack.ga_len;
12188a7d6542SBram Moolenaar 		    clear_tv(sv->sv_tv);
12198a7d6542SBram Moolenaar 		    *sv->sv_tv = *STACK_TV_BOT(0);
12208a7d6542SBram Moolenaar 		}
12218a7d6542SBram Moolenaar 		break;
12228a7d6542SBram Moolenaar 
12238a7d6542SBram Moolenaar 	    // store option
12248a7d6542SBram Moolenaar 	    case ISN_STOREOPT:
12258a7d6542SBram Moolenaar 		{
12268a7d6542SBram Moolenaar 		    long	n = 0;
12278a7d6542SBram Moolenaar 		    char_u	*s = NULL;
12288a7d6542SBram Moolenaar 		    char	*msg;
12298a7d6542SBram Moolenaar 
12308a7d6542SBram Moolenaar 		    --ectx.ec_stack.ga_len;
12318a7d6542SBram Moolenaar 		    tv = STACK_TV_BOT(0);
12328a7d6542SBram Moolenaar 		    if (tv->v_type == VAR_STRING)
123397a2af39SBram Moolenaar 		    {
12348a7d6542SBram Moolenaar 			s = tv->vval.v_string;
123597a2af39SBram Moolenaar 			if (s == NULL)
123697a2af39SBram Moolenaar 			    s = (char_u *)"";
123797a2af39SBram Moolenaar 		    }
12388a7d6542SBram Moolenaar 		    else
1239a6e67e4fSBram Moolenaar 			// must be VAR_NUMBER, CHECKTYPE makes sure
1240a6e67e4fSBram Moolenaar 			n = tv->vval.v_number;
12418a7d6542SBram Moolenaar 		    msg = set_option_value(iptr->isn_arg.storeopt.so_name,
12428a7d6542SBram Moolenaar 					n, s, iptr->isn_arg.storeopt.so_flags);
1243e75ba268SBram Moolenaar 		    clear_tv(tv);
12448a7d6542SBram Moolenaar 		    if (msg != NULL)
12458a7d6542SBram Moolenaar 		    {
12468a7d6542SBram Moolenaar 			emsg(_(msg));
1247e859312eSBram Moolenaar 			goto on_error;
12488a7d6542SBram Moolenaar 		    }
12498a7d6542SBram Moolenaar 		}
12508a7d6542SBram Moolenaar 		break;
12518a7d6542SBram Moolenaar 
1252b283a8a6SBram Moolenaar 	    // store $ENV
1253b283a8a6SBram Moolenaar 	    case ISN_STOREENV:
1254b283a8a6SBram Moolenaar 		--ectx.ec_stack.ga_len;
125520431c9dSBram Moolenaar 		tv = STACK_TV_BOT(0);
125620431c9dSBram Moolenaar 		vim_setenv_ext(iptr->isn_arg.string, tv_get_string(tv));
125720431c9dSBram Moolenaar 		clear_tv(tv);
1258b283a8a6SBram Moolenaar 		break;
1259b283a8a6SBram Moolenaar 
1260b283a8a6SBram Moolenaar 	    // store @r
1261b283a8a6SBram Moolenaar 	    case ISN_STOREREG:
1262b283a8a6SBram Moolenaar 		{
1263b283a8a6SBram Moolenaar 		    int	reg = iptr->isn_arg.number;
1264b283a8a6SBram Moolenaar 
1265b283a8a6SBram Moolenaar 		    --ectx.ec_stack.ga_len;
1266401d9ffbSBram Moolenaar 		    tv = STACK_TV_BOT(0);
1267b283a8a6SBram Moolenaar 		    write_reg_contents(reg == '@' ? '"' : reg,
1268401d9ffbSBram Moolenaar 						 tv_get_string(tv), -1, FALSE);
1269401d9ffbSBram Moolenaar 		    clear_tv(tv);
1270b283a8a6SBram Moolenaar 		}
1271b283a8a6SBram Moolenaar 		break;
1272b283a8a6SBram Moolenaar 
1273b283a8a6SBram Moolenaar 	    // store v: variable
1274b283a8a6SBram Moolenaar 	    case ISN_STOREV:
1275b283a8a6SBram Moolenaar 		--ectx.ec_stack.ga_len;
1276b283a8a6SBram Moolenaar 		if (set_vim_var_tv(iptr->isn_arg.number, STACK_TV_BOT(0))
1277b283a8a6SBram Moolenaar 								       == FAIL)
1278e859312eSBram Moolenaar 		    // should not happen, type is checked when compiling
1279e859312eSBram Moolenaar 		    goto on_error;
1280b283a8a6SBram Moolenaar 		break;
1281b283a8a6SBram Moolenaar 
1282d3aac291SBram Moolenaar 	    // store g:/b:/w:/t: variable
12838a7d6542SBram Moolenaar 	    case ISN_STOREG:
1284d3aac291SBram Moolenaar 	    case ISN_STOREB:
1285d3aac291SBram Moolenaar 	    case ISN_STOREW:
1286d3aac291SBram Moolenaar 	    case ISN_STORET:
12878a7d6542SBram Moolenaar 		{
12888a7d6542SBram Moolenaar 		    dictitem_T *di;
1289d3aac291SBram Moolenaar 		    hashtab_T *ht;
1290d3aac291SBram Moolenaar 		    switch (iptr->isn_type)
1291d3aac291SBram Moolenaar 		    {
1292d3aac291SBram Moolenaar 			case ISN_STOREG:
1293d3aac291SBram Moolenaar 			    ht = get_globvar_ht();
1294d3aac291SBram Moolenaar 			    break;
1295d3aac291SBram Moolenaar 			case ISN_STOREB:
1296d3aac291SBram Moolenaar 			    ht = &curbuf->b_vars->dv_hashtab;
1297d3aac291SBram Moolenaar 			    break;
1298d3aac291SBram Moolenaar 			case ISN_STOREW:
1299d3aac291SBram Moolenaar 			    ht = &curwin->w_vars->dv_hashtab;
1300d3aac291SBram Moolenaar 			    break;
1301d3aac291SBram Moolenaar 			case ISN_STORET:
1302d3aac291SBram Moolenaar 			    ht = &curtab->tp_vars->dv_hashtab;
1303d3aac291SBram Moolenaar 			    break;
1304d3aac291SBram Moolenaar 			default:  // Cannot reach here
1305d3aac291SBram Moolenaar 			    goto failed;
1306d3aac291SBram Moolenaar 		    }
13078a7d6542SBram Moolenaar 
13088a7d6542SBram Moolenaar 		    --ectx.ec_stack.ga_len;
1309bf67ea1aSBram Moolenaar 		    di = find_var_in_ht(ht, 0, iptr->isn_arg.string + 2, TRUE);
13108a7d6542SBram Moolenaar 		    if (di == NULL)
13110bbf722aSBram Moolenaar 			store_var(iptr->isn_arg.string, STACK_TV_BOT(0));
13128a7d6542SBram Moolenaar 		    else
13138a7d6542SBram Moolenaar 		    {
13148a7d6542SBram Moolenaar 			clear_tv(&di->di_tv);
13158a7d6542SBram Moolenaar 			di->di_tv = *STACK_TV_BOT(0);
13168a7d6542SBram Moolenaar 		    }
13178a7d6542SBram Moolenaar 		}
13188a7d6542SBram Moolenaar 		break;
13198a7d6542SBram Moolenaar 
13208a7d6542SBram Moolenaar 	    // store number in local variable
13218a7d6542SBram Moolenaar 	    case ISN_STORENR:
1322a471eeaeSBram Moolenaar 		tv = STACK_TV_VAR(iptr->isn_arg.storenr.stnr_idx);
13238a7d6542SBram Moolenaar 		clear_tv(tv);
13248a7d6542SBram Moolenaar 		tv->v_type = VAR_NUMBER;
1325a471eeaeSBram Moolenaar 		tv->vval.v_number = iptr->isn_arg.storenr.stnr_val;
13268a7d6542SBram Moolenaar 		break;
13278a7d6542SBram Moolenaar 
13281cc2a94fSBram Moolenaar 	    // store value in list variable
13291cc2a94fSBram Moolenaar 	    case ISN_STORELIST:
13301cc2a94fSBram Moolenaar 		{
13311cc2a94fSBram Moolenaar 		    typval_T	*tv_idx = STACK_TV_BOT(-2);
13321cc2a94fSBram Moolenaar 		    varnumber_T	lidx = tv_idx->vval.v_number;
13331cc2a94fSBram Moolenaar 		    typval_T	*tv_list = STACK_TV_BOT(-1);
13341cc2a94fSBram Moolenaar 		    list_T	*list = tv_list->vval.v_list;
13351cc2a94fSBram Moolenaar 
13361cc2a94fSBram Moolenaar 		    if (lidx < 0 && list->lv_len + lidx >= 0)
13371cc2a94fSBram Moolenaar 			// negative index is relative to the end
13381cc2a94fSBram Moolenaar 			lidx = list->lv_len + lidx;
13391cc2a94fSBram Moolenaar 		    if (lidx < 0 || lidx > list->lv_len)
13401cc2a94fSBram Moolenaar 		    {
13411cc2a94fSBram Moolenaar 			semsg(_(e_listidx), lidx);
1342e859312eSBram Moolenaar 			goto on_error;
13431cc2a94fSBram Moolenaar 		    }
13441cc2a94fSBram Moolenaar 		    tv = STACK_TV_BOT(-3);
13451cc2a94fSBram Moolenaar 		    if (lidx < list->lv_len)
13461cc2a94fSBram Moolenaar 		    {
13471cc2a94fSBram Moolenaar 			listitem_T *li = list_find(list, lidx);
13481cc2a94fSBram Moolenaar 
13491cc2a94fSBram Moolenaar 			// overwrite existing list item
13501cc2a94fSBram Moolenaar 			clear_tv(&li->li_tv);
13511cc2a94fSBram Moolenaar 			li->li_tv = *tv;
13521cc2a94fSBram Moolenaar 		    }
13531cc2a94fSBram Moolenaar 		    else
13541cc2a94fSBram Moolenaar 		    {
1355e859312eSBram Moolenaar 			// append to list, only fails when out of memory
13561cc2a94fSBram Moolenaar 			if (list_append_tv(list, tv) == FAIL)
13571cc2a94fSBram Moolenaar 			    goto failed;
13581cc2a94fSBram Moolenaar 			clear_tv(tv);
13591cc2a94fSBram Moolenaar 		    }
13601cc2a94fSBram Moolenaar 		    clear_tv(tv_idx);
13611cc2a94fSBram Moolenaar 		    clear_tv(tv_list);
1362f163bd5eSBram Moolenaar 		    ectx.ec_stack.ga_len -= 3;
13631cc2a94fSBram Moolenaar 		}
13641cc2a94fSBram Moolenaar 		break;
13651cc2a94fSBram Moolenaar 
13661cc2a94fSBram Moolenaar 	    // store value in dict variable
13671cc2a94fSBram Moolenaar 	    case ISN_STOREDICT:
13681cc2a94fSBram Moolenaar 		{
13691cc2a94fSBram Moolenaar 		    typval_T	*tv_key = STACK_TV_BOT(-2);
13701cc2a94fSBram Moolenaar 		    char_u	*key = tv_key->vval.v_string;
13711cc2a94fSBram Moolenaar 		    typval_T	*tv_dict = STACK_TV_BOT(-1);
13721cc2a94fSBram Moolenaar 		    dict_T	*dict = tv_dict->vval.v_dict;
13731cc2a94fSBram Moolenaar 		    dictitem_T	*di;
13741cc2a94fSBram Moolenaar 
13751cc2a94fSBram Moolenaar 		    if (key == NULL || *key == NUL)
13761cc2a94fSBram Moolenaar 		    {
13771cc2a94fSBram Moolenaar 			emsg(_(e_emptykey));
1378e859312eSBram Moolenaar 			goto on_error;
13791cc2a94fSBram Moolenaar 		    }
13801cc2a94fSBram Moolenaar 		    tv = STACK_TV_BOT(-3);
13811cc2a94fSBram Moolenaar 		    di = dict_find(dict, key, -1);
13821cc2a94fSBram Moolenaar 		    if (di != NULL)
13831cc2a94fSBram Moolenaar 		    {
1384e859312eSBram Moolenaar 			// overwrite existing value
13851cc2a94fSBram Moolenaar 			clear_tv(&di->di_tv);
13861cc2a94fSBram Moolenaar 			di->di_tv = *tv;
13871cc2a94fSBram Moolenaar 		    }
13881cc2a94fSBram Moolenaar 		    else
13891cc2a94fSBram Moolenaar 		    {
1390e859312eSBram Moolenaar 			// add to dict, only fails when out of memory
13911cc2a94fSBram Moolenaar 			if (dict_add_tv(dict, (char *)key, tv) == FAIL)
13921cc2a94fSBram Moolenaar 			    goto failed;
13931cc2a94fSBram Moolenaar 			clear_tv(tv);
13941cc2a94fSBram Moolenaar 		    }
13951cc2a94fSBram Moolenaar 		    clear_tv(tv_key);
13961cc2a94fSBram Moolenaar 		    clear_tv(tv_dict);
1397f163bd5eSBram Moolenaar 		    ectx.ec_stack.ga_len -= 3;
13981cc2a94fSBram Moolenaar 		}
13991cc2a94fSBram Moolenaar 		break;
14001cc2a94fSBram Moolenaar 
14018a7d6542SBram Moolenaar 	    // push constant
14028a7d6542SBram Moolenaar 	    case ISN_PUSHNR:
14038a7d6542SBram Moolenaar 	    case ISN_PUSHBOOL:
14048a7d6542SBram Moolenaar 	    case ISN_PUSHSPEC:
14058a7d6542SBram Moolenaar 	    case ISN_PUSHF:
14068a7d6542SBram Moolenaar 	    case ISN_PUSHS:
14078a7d6542SBram Moolenaar 	    case ISN_PUSHBLOB:
140842a480bfSBram Moolenaar 	    case ISN_PUSHFUNC:
140942a480bfSBram Moolenaar 	    case ISN_PUSHCHANNEL:
141042a480bfSBram Moolenaar 	    case ISN_PUSHJOB:
1411270d0388SBram Moolenaar 		if (GA_GROW(&ectx.ec_stack, 1) == FAIL)
14128a7d6542SBram Moolenaar 		    goto failed;
14138a7d6542SBram Moolenaar 		tv = STACK_TV_BOT(0);
14148a7d6542SBram Moolenaar 		++ectx.ec_stack.ga_len;
14158a7d6542SBram Moolenaar 		switch (iptr->isn_type)
14168a7d6542SBram Moolenaar 		{
14178a7d6542SBram Moolenaar 		    case ISN_PUSHNR:
14188a7d6542SBram Moolenaar 			tv->v_type = VAR_NUMBER;
14198a7d6542SBram Moolenaar 			tv->vval.v_number = iptr->isn_arg.number;
14208a7d6542SBram Moolenaar 			break;
14218a7d6542SBram Moolenaar 		    case ISN_PUSHBOOL:
14228a7d6542SBram Moolenaar 			tv->v_type = VAR_BOOL;
14238a7d6542SBram Moolenaar 			tv->vval.v_number = iptr->isn_arg.number;
14248a7d6542SBram Moolenaar 			break;
14258a7d6542SBram Moolenaar 		    case ISN_PUSHSPEC:
14268a7d6542SBram Moolenaar 			tv->v_type = VAR_SPECIAL;
14278a7d6542SBram Moolenaar 			tv->vval.v_number = iptr->isn_arg.number;
14288a7d6542SBram Moolenaar 			break;
14298a7d6542SBram Moolenaar #ifdef FEAT_FLOAT
14308a7d6542SBram Moolenaar 		    case ISN_PUSHF:
14318a7d6542SBram Moolenaar 			tv->v_type = VAR_FLOAT;
14328a7d6542SBram Moolenaar 			tv->vval.v_float = iptr->isn_arg.fnumber;
14338a7d6542SBram Moolenaar 			break;
14348a7d6542SBram Moolenaar #endif
14358a7d6542SBram Moolenaar 		    case ISN_PUSHBLOB:
14368a7d6542SBram Moolenaar 			blob_copy(iptr->isn_arg.blob, tv);
14378a7d6542SBram Moolenaar 			break;
143842a480bfSBram Moolenaar 		    case ISN_PUSHFUNC:
143942a480bfSBram Moolenaar 			tv->v_type = VAR_FUNC;
1440087d2e15SBram Moolenaar 			if (iptr->isn_arg.string == NULL)
1441087d2e15SBram Moolenaar 			    tv->vval.v_string = NULL;
1442087d2e15SBram Moolenaar 			else
1443087d2e15SBram Moolenaar 			    tv->vval.v_string =
1444087d2e15SBram Moolenaar 					     vim_strsave(iptr->isn_arg.string);
144542a480bfSBram Moolenaar 			break;
144642a480bfSBram Moolenaar 		    case ISN_PUSHCHANNEL:
144742a480bfSBram Moolenaar #ifdef FEAT_JOB_CHANNEL
144842a480bfSBram Moolenaar 			tv->v_type = VAR_CHANNEL;
144942a480bfSBram Moolenaar 			tv->vval.v_channel = iptr->isn_arg.channel;
145042a480bfSBram Moolenaar 			if (tv->vval.v_channel != NULL)
145142a480bfSBram Moolenaar 			    ++tv->vval.v_channel->ch_refcount;
145242a480bfSBram Moolenaar #endif
145342a480bfSBram Moolenaar 			break;
145442a480bfSBram Moolenaar 		    case ISN_PUSHJOB:
145542a480bfSBram Moolenaar #ifdef FEAT_JOB_CHANNEL
145642a480bfSBram Moolenaar 			tv->v_type = VAR_JOB;
145742a480bfSBram Moolenaar 			tv->vval.v_job = iptr->isn_arg.job;
145842a480bfSBram Moolenaar 			if (tv->vval.v_job != NULL)
145942a480bfSBram Moolenaar 			    ++tv->vval.v_job->jv_refcount;
146042a480bfSBram Moolenaar #endif
146142a480bfSBram Moolenaar 			break;
14628a7d6542SBram Moolenaar 		    default:
14638a7d6542SBram Moolenaar 			tv->v_type = VAR_STRING;
1464e69f6d04SBram Moolenaar 			tv->vval.v_string = vim_strsave(
1465e69f6d04SBram Moolenaar 				iptr->isn_arg.string == NULL
1466e69f6d04SBram Moolenaar 					? (char_u *)"" : iptr->isn_arg.string);
14678a7d6542SBram Moolenaar 		}
14688a7d6542SBram Moolenaar 		break;
14698a7d6542SBram Moolenaar 
1470d72c1bf0SBram Moolenaar 	    case ISN_UNLET:
1471d72c1bf0SBram Moolenaar 		if (do_unlet(iptr->isn_arg.unlet.ul_name,
1472d72c1bf0SBram Moolenaar 				       iptr->isn_arg.unlet.ul_forceit) == FAIL)
1473e859312eSBram Moolenaar 		    goto on_error;
1474d72c1bf0SBram Moolenaar 		break;
14757bdaea6eSBram Moolenaar 	    case ISN_UNLETENV:
14767bdaea6eSBram Moolenaar 		vim_unsetenv(iptr->isn_arg.unlet.ul_name);
14777bdaea6eSBram Moolenaar 		break;
1478d72c1bf0SBram Moolenaar 
14798a7d6542SBram Moolenaar 	    // create a list from items on the stack; uses a single allocation
14808a7d6542SBram Moolenaar 	    // for the list header and the items
14818a7d6542SBram Moolenaar 	    case ISN_NEWLIST:
1482fe270817SBram Moolenaar 		if (exe_newlist(iptr->isn_arg.number, &ectx) == FAIL)
14838a7d6542SBram Moolenaar 		    goto failed;
14848a7d6542SBram Moolenaar 		break;
14858a7d6542SBram Moolenaar 
14868a7d6542SBram Moolenaar 	    // create a dict from items on the stack
14878a7d6542SBram Moolenaar 	    case ISN_NEWDICT:
14888a7d6542SBram Moolenaar 		{
14898a7d6542SBram Moolenaar 		    int		count = iptr->isn_arg.number;
14908a7d6542SBram Moolenaar 		    dict_T	*dict = dict_alloc();
14918a7d6542SBram Moolenaar 		    dictitem_T	*item;
14928a7d6542SBram Moolenaar 
14938a7d6542SBram Moolenaar 		    if (dict == NULL)
14948a7d6542SBram Moolenaar 			goto failed;
14958a7d6542SBram Moolenaar 		    for (idx = 0; idx < count; ++idx)
14968a7d6542SBram Moolenaar 		    {
1497e859312eSBram Moolenaar 			// have already checked key type is VAR_STRING
14988a7d6542SBram Moolenaar 			tv = STACK_TV_BOT(2 * (idx - count));
1499e859312eSBram Moolenaar 			// check key is unique
1500e859312eSBram Moolenaar 			item = dict_find(dict, tv->vval.v_string, -1);
1501e859312eSBram Moolenaar 			if (item != NULL)
1502e859312eSBram Moolenaar 			{
1503e859312eSBram Moolenaar 			    semsg(_(e_duplicate_key), tv->vval.v_string);
1504e859312eSBram Moolenaar 			    dict_unref(dict);
1505e859312eSBram Moolenaar 			    goto on_error;
1506e859312eSBram Moolenaar 			}
15078a7d6542SBram Moolenaar 			item = dictitem_alloc(tv->vval.v_string);
15088a7d6542SBram Moolenaar 			clear_tv(tv);
15098a7d6542SBram Moolenaar 			if (item == NULL)
1510e859312eSBram Moolenaar 			{
1511e859312eSBram Moolenaar 			    dict_unref(dict);
15128a7d6542SBram Moolenaar 			    goto failed;
1513e859312eSBram Moolenaar 			}
15148a7d6542SBram Moolenaar 			item->di_tv = *STACK_TV_BOT(2 * (idx - count) + 1);
15158a7d6542SBram Moolenaar 			item->di_tv.v_lock = 0;
15168a7d6542SBram Moolenaar 			if (dict_add(dict, item) == FAIL)
1517e859312eSBram Moolenaar 			{
1518d032f34aSBram Moolenaar 			    // can this ever happen?
1519e859312eSBram Moolenaar 			    dict_unref(dict);
15208a7d6542SBram Moolenaar 			    goto failed;
15218a7d6542SBram Moolenaar 			}
1522e859312eSBram Moolenaar 		    }
15238a7d6542SBram Moolenaar 
15248a7d6542SBram Moolenaar 		    if (count > 0)
15258a7d6542SBram Moolenaar 			ectx.ec_stack.ga_len -= 2 * count - 1;
1526270d0388SBram Moolenaar 		    else if (GA_GROW(&ectx.ec_stack, 1) == FAIL)
15278a7d6542SBram Moolenaar 			goto failed;
15288a7d6542SBram Moolenaar 		    else
15298a7d6542SBram Moolenaar 			++ectx.ec_stack.ga_len;
15308a7d6542SBram Moolenaar 		    tv = STACK_TV_BOT(-1);
15318a7d6542SBram Moolenaar 		    tv->v_type = VAR_DICT;
15328a7d6542SBram Moolenaar 		    tv->vval.v_dict = dict;
15338a7d6542SBram Moolenaar 		    ++dict->dv_refcount;
15348a7d6542SBram Moolenaar 		}
15358a7d6542SBram Moolenaar 		break;
15368a7d6542SBram Moolenaar 
15378a7d6542SBram Moolenaar 	    // call a :def function
15388a7d6542SBram Moolenaar 	    case ISN_DCALL:
15398a7d6542SBram Moolenaar 		if (call_dfunc(iptr->isn_arg.dfunc.cdf_idx,
15408a7d6542SBram Moolenaar 			      iptr->isn_arg.dfunc.cdf_argcount,
15418a7d6542SBram Moolenaar 			      &ectx) == FAIL)
1542e859312eSBram Moolenaar 		    goto on_error;
15438a7d6542SBram Moolenaar 		break;
15448a7d6542SBram Moolenaar 
15458a7d6542SBram Moolenaar 	    // call a builtin function
15468a7d6542SBram Moolenaar 	    case ISN_BCALL:
15478a7d6542SBram Moolenaar 		SOURCING_LNUM = iptr->isn_lnum;
15488a7d6542SBram Moolenaar 		if (call_bfunc(iptr->isn_arg.bfunc.cbf_idx,
15498a7d6542SBram Moolenaar 			      iptr->isn_arg.bfunc.cbf_argcount,
15508a7d6542SBram Moolenaar 			      &ectx) == FAIL)
1551d032f34aSBram Moolenaar 		    goto on_error;
15528a7d6542SBram Moolenaar 		break;
15538a7d6542SBram Moolenaar 
15548a7d6542SBram Moolenaar 	    // call a funcref or partial
15558a7d6542SBram Moolenaar 	    case ISN_PCALL:
15568a7d6542SBram Moolenaar 		{
15578a7d6542SBram Moolenaar 		    cpfunc_T	*pfunc = &iptr->isn_arg.pfunc;
15588a7d6542SBram Moolenaar 		    int		r;
15596f5b6dfbSBram Moolenaar 		    typval_T	partial_tv;
15608a7d6542SBram Moolenaar 
15618a7d6542SBram Moolenaar 		    SOURCING_LNUM = iptr->isn_lnum;
15628a7d6542SBram Moolenaar 		    if (pfunc->cpf_top)
15638a7d6542SBram Moolenaar 		    {
15648a7d6542SBram Moolenaar 			// funcref is above the arguments
15658a7d6542SBram Moolenaar 			tv = STACK_TV_BOT(-pfunc->cpf_argcount - 1);
15668a7d6542SBram Moolenaar 		    }
15678a7d6542SBram Moolenaar 		    else
15688a7d6542SBram Moolenaar 		    {
15698a7d6542SBram Moolenaar 			// Get the funcref from the stack.
15708a7d6542SBram Moolenaar 			--ectx.ec_stack.ga_len;
15716f5b6dfbSBram Moolenaar 			partial_tv = *STACK_TV_BOT(0);
15726f5b6dfbSBram Moolenaar 			tv = &partial_tv;
15738a7d6542SBram Moolenaar 		    }
15748a7d6542SBram Moolenaar 		    r = call_partial(tv, pfunc->cpf_argcount, &ectx);
15756f5b6dfbSBram Moolenaar 		    if (tv == &partial_tv)
15766f5b6dfbSBram Moolenaar 			clear_tv(&partial_tv);
15778a7d6542SBram Moolenaar 		    if (r == FAIL)
1578d032f34aSBram Moolenaar 			goto on_error;
1579bd5da371SBram Moolenaar 		}
1580bd5da371SBram Moolenaar 		break;
15818a7d6542SBram Moolenaar 
1582bd5da371SBram Moolenaar 	    case ISN_PCALL_END:
1583bd5da371SBram Moolenaar 		// PCALL finished, arguments have been consumed and replaced by
1584bd5da371SBram Moolenaar 		// the return value.  Now clear the funcref from the stack,
1585bd5da371SBram Moolenaar 		// and move the return value in its place.
15868a7d6542SBram Moolenaar 		--ectx.ec_stack.ga_len;
1587bd5da371SBram Moolenaar 		clear_tv(STACK_TV_BOT(-1));
15888a7d6542SBram Moolenaar 		*STACK_TV_BOT(-1) = *STACK_TV_BOT(0);
15898a7d6542SBram Moolenaar 		break;
15908a7d6542SBram Moolenaar 
15918a7d6542SBram Moolenaar 	    // call a user defined function or funcref/partial
15928a7d6542SBram Moolenaar 	    case ISN_UCALL:
15938a7d6542SBram Moolenaar 		{
15948a7d6542SBram Moolenaar 		    cufunc_T	*cufunc = &iptr->isn_arg.ufunc;
15958a7d6542SBram Moolenaar 
15968a7d6542SBram Moolenaar 		    SOURCING_LNUM = iptr->isn_lnum;
15978a7d6542SBram Moolenaar 		    if (call_eval_func(cufunc->cuf_name,
15987eeefd4aSBram Moolenaar 				    cufunc->cuf_argcount, &ectx, iptr) == FAIL)
1599d032f34aSBram Moolenaar 			goto on_error;
16008a7d6542SBram Moolenaar 		}
16018a7d6542SBram Moolenaar 		break;
16028a7d6542SBram Moolenaar 
16038a7d6542SBram Moolenaar 	    // return from a :def function call
16048a7d6542SBram Moolenaar 	    case ISN_RETURN:
16058a7d6542SBram Moolenaar 		{
16068cbd6dfcSBram Moolenaar 		    garray_T	*trystack = &ectx.ec_trystack;
160720431c9dSBram Moolenaar 		    trycmd_T    *trycmd = NULL;
16088cbd6dfcSBram Moolenaar 
16098cbd6dfcSBram Moolenaar 		    if (trystack->ga_len > 0)
16108cbd6dfcSBram Moolenaar 			trycmd = ((trycmd_T *)trystack->ga_data)
16118cbd6dfcSBram Moolenaar 							+ trystack->ga_len - 1;
1612bf67ea1aSBram Moolenaar 		    if (trycmd != NULL
1613bf67ea1aSBram Moolenaar 				  && trycmd->tcd_frame_idx == ectx.ec_frame_idx
16148a7d6542SBram Moolenaar 			    && trycmd->tcd_finally_idx != 0)
16158a7d6542SBram Moolenaar 		    {
16168a7d6542SBram Moolenaar 			// jump to ":finally"
16178a7d6542SBram Moolenaar 			ectx.ec_iidx = trycmd->tcd_finally_idx;
16188a7d6542SBram Moolenaar 			trycmd->tcd_return = TRUE;
16198a7d6542SBram Moolenaar 		    }
16208a7d6542SBram Moolenaar 		    else
1621d032f34aSBram Moolenaar 			goto func_return;
16228a7d6542SBram Moolenaar 		}
16238a7d6542SBram Moolenaar 		break;
16248a7d6542SBram Moolenaar 
16258a7d6542SBram Moolenaar 	    // push a function reference to a compiled function
16268a7d6542SBram Moolenaar 	    case ISN_FUNCREF:
16278a7d6542SBram Moolenaar 		{
16288a7d6542SBram Moolenaar 		    partial_T   *pt = NULL;
1629bf67ea1aSBram Moolenaar 		    dfunc_T	*pt_dfunc;
16308a7d6542SBram Moolenaar 
16318a7d6542SBram Moolenaar 		    pt = ALLOC_CLEAR_ONE(partial_T);
16328a7d6542SBram Moolenaar 		    if (pt == NULL)
16338a7d6542SBram Moolenaar 			goto failed;
1634270d0388SBram Moolenaar 		    if (GA_GROW(&ectx.ec_stack, 1) == FAIL)
1635c8cd2b34SBram Moolenaar 		    {
1636bf67ea1aSBram Moolenaar 			vim_free(pt);
1637bf67ea1aSBram Moolenaar 			goto failed;
1638bf67ea1aSBram Moolenaar 		    }
1639bf67ea1aSBram Moolenaar 		    pt_dfunc = ((dfunc_T *)def_functions.ga_data)
1640bf67ea1aSBram Moolenaar 					       + iptr->isn_arg.funcref.fr_func;
1641bf67ea1aSBram Moolenaar 		    pt->pt_func = pt_dfunc->df_ufunc;
1642bf67ea1aSBram Moolenaar 		    pt->pt_refcount = 1;
1643bf67ea1aSBram Moolenaar 		    ++pt_dfunc->df_ufunc->uf_refcount;
1644bf67ea1aSBram Moolenaar 
1645bf67ea1aSBram Moolenaar 		    if (pt_dfunc->df_ufunc->uf_flags & FC_CLOSURE)
1646bf67ea1aSBram Moolenaar 		    {
1647bf67ea1aSBram Moolenaar 			dfunc_T	*dfunc = ((dfunc_T *)def_functions.ga_data)
1648bf67ea1aSBram Moolenaar 							   + ectx.ec_dfunc_idx;
1649bf67ea1aSBram Moolenaar 
1650bf67ea1aSBram Moolenaar 			// The closure needs to find arguments and local
1651bf67ea1aSBram Moolenaar 			// variables in the current stack.
1652f7779c63SBram Moolenaar 			pt->pt_ectx_stack = &ectx.ec_stack;
1653f7779c63SBram Moolenaar 			pt->pt_ectx_frame = ectx.ec_frame_idx;
1654bf67ea1aSBram Moolenaar 
1655bf67ea1aSBram Moolenaar 			// If this function returns and the closure is still
1656bf67ea1aSBram Moolenaar 			// used, we need to make a copy of the context
1657bf67ea1aSBram Moolenaar 			// (arguments and local variables). Store a reference
1658bf67ea1aSBram Moolenaar 			// to the partial so we can handle that.
1659bf67ea1aSBram Moolenaar 			++pt->pt_refcount;
1660bf67ea1aSBram Moolenaar 			tv = STACK_TV_VAR(dfunc->df_varcount
1661bf67ea1aSBram Moolenaar 					   + iptr->isn_arg.funcref.fr_var_idx);
1662bf67ea1aSBram Moolenaar 			if (tv->v_type == VAR_PARTIAL)
1663bf67ea1aSBram Moolenaar 			{
1664bf67ea1aSBram Moolenaar 			    // TODO: use a garray_T on ectx.
1665bf67ea1aSBram Moolenaar 			    emsg("Multiple closures not supported yet");
1666bf67ea1aSBram Moolenaar 			    goto failed;
1667bf67ea1aSBram Moolenaar 			}
1668bf67ea1aSBram Moolenaar 			tv->v_type = VAR_PARTIAL;
1669bf67ea1aSBram Moolenaar 			tv->vval.v_partial = pt;
1670c8cd2b34SBram Moolenaar 		    }
1671c8cd2b34SBram Moolenaar 
16728a7d6542SBram Moolenaar 		    tv = STACK_TV_BOT(0);
16738a7d6542SBram Moolenaar 		    ++ectx.ec_stack.ga_len;
16748a7d6542SBram Moolenaar 		    tv->vval.v_partial = pt;
16758a7d6542SBram Moolenaar 		    tv->v_type = VAR_PARTIAL;
16768a7d6542SBram Moolenaar 		}
16778a7d6542SBram Moolenaar 		break;
16788a7d6542SBram Moolenaar 
16798a7d6542SBram Moolenaar 	    // jump if a condition is met
16808a7d6542SBram Moolenaar 	    case ISN_JUMP:
16818a7d6542SBram Moolenaar 		{
16828a7d6542SBram Moolenaar 		    jumpwhen_T	when = iptr->isn_arg.jump.jump_when;
16838a7d6542SBram Moolenaar 		    int		jump = TRUE;
16848a7d6542SBram Moolenaar 
16858a7d6542SBram Moolenaar 		    if (when != JUMP_ALWAYS)
16868a7d6542SBram Moolenaar 		    {
16878a7d6542SBram Moolenaar 			tv = STACK_TV_BOT(-1);
16888a7d6542SBram Moolenaar 			jump = tv2bool(tv);
16898a7d6542SBram Moolenaar 			if (when == JUMP_IF_FALSE
16908a7d6542SBram Moolenaar 					     || when == JUMP_AND_KEEP_IF_FALSE)
16918a7d6542SBram Moolenaar 			    jump = !jump;
1692777770fbSBram Moolenaar 			if (when == JUMP_IF_FALSE || !jump)
16938a7d6542SBram Moolenaar 			{
16948a7d6542SBram Moolenaar 			    // drop the value from the stack
16958a7d6542SBram Moolenaar 			    clear_tv(tv);
16968a7d6542SBram Moolenaar 			    --ectx.ec_stack.ga_len;
16978a7d6542SBram Moolenaar 			}
16988a7d6542SBram Moolenaar 		    }
16998a7d6542SBram Moolenaar 		    if (jump)
17008a7d6542SBram Moolenaar 			ectx.ec_iidx = iptr->isn_arg.jump.jump_where;
17018a7d6542SBram Moolenaar 		}
17028a7d6542SBram Moolenaar 		break;
17038a7d6542SBram Moolenaar 
17048a7d6542SBram Moolenaar 	    // top of a for loop
17058a7d6542SBram Moolenaar 	    case ISN_FOR:
17068a7d6542SBram Moolenaar 		{
17078a7d6542SBram Moolenaar 		    list_T	*list = STACK_TV_BOT(-1)->vval.v_list;
17088a7d6542SBram Moolenaar 		    typval_T	*idxtv =
17098a7d6542SBram Moolenaar 				   STACK_TV_VAR(iptr->isn_arg.forloop.for_idx);
17108a7d6542SBram Moolenaar 
17118a7d6542SBram Moolenaar 		    // push the next item from the list
1712270d0388SBram Moolenaar 		    if (GA_GROW(&ectx.ec_stack, 1) == FAIL)
17138a7d6542SBram Moolenaar 			goto failed;
17148a7d6542SBram Moolenaar 		    if (++idxtv->vval.v_number >= list->lv_len)
17158a7d6542SBram Moolenaar 			// past the end of the list, jump to "endfor"
17168a7d6542SBram Moolenaar 			ectx.ec_iidx = iptr->isn_arg.forloop.for_end;
17178a7d6542SBram Moolenaar 		    else if (list->lv_first == &range_list_item)
17188a7d6542SBram Moolenaar 		    {
17198a7d6542SBram Moolenaar 			// non-materialized range() list
17208a7d6542SBram Moolenaar 			tv = STACK_TV_BOT(0);
17218a7d6542SBram Moolenaar 			tv->v_type = VAR_NUMBER;
17228a7d6542SBram Moolenaar 			tv->vval.v_number = list_find_nr(
17238a7d6542SBram Moolenaar 					     list, idxtv->vval.v_number, NULL);
17248a7d6542SBram Moolenaar 			++ectx.ec_stack.ga_len;
17258a7d6542SBram Moolenaar 		    }
17268a7d6542SBram Moolenaar 		    else
17278a7d6542SBram Moolenaar 		    {
17288a7d6542SBram Moolenaar 			listitem_T *li = list_find(list, idxtv->vval.v_number);
17298a7d6542SBram Moolenaar 
17308a7d6542SBram Moolenaar 			copy_tv(&li->li_tv, STACK_TV_BOT(0));
17318a7d6542SBram Moolenaar 			++ectx.ec_stack.ga_len;
17328a7d6542SBram Moolenaar 		    }
17338a7d6542SBram Moolenaar 		}
17348a7d6542SBram Moolenaar 		break;
17358a7d6542SBram Moolenaar 
17368a7d6542SBram Moolenaar 	    // start of ":try" block
17378a7d6542SBram Moolenaar 	    case ISN_TRY:
17388a7d6542SBram Moolenaar 		{
173920431c9dSBram Moolenaar 		    trycmd_T    *trycmd = NULL;
174020431c9dSBram Moolenaar 
1741270d0388SBram Moolenaar 		    if (GA_GROW(&ectx.ec_trystack, 1) == FAIL)
17428a7d6542SBram Moolenaar 			goto failed;
17438a7d6542SBram Moolenaar 		    trycmd = ((trycmd_T *)ectx.ec_trystack.ga_data)
17448a7d6542SBram Moolenaar 						     + ectx.ec_trystack.ga_len;
17458a7d6542SBram Moolenaar 		    ++ectx.ec_trystack.ga_len;
17468a7d6542SBram Moolenaar 		    ++trylevel;
1747bf67ea1aSBram Moolenaar 		    trycmd->tcd_frame_idx = ectx.ec_frame_idx;
17488a7d6542SBram Moolenaar 		    trycmd->tcd_catch_idx = iptr->isn_arg.try.try_catch;
17498a7d6542SBram Moolenaar 		    trycmd->tcd_finally_idx = iptr->isn_arg.try.try_finally;
1750f575adffSBram Moolenaar 		    trycmd->tcd_caught = FALSE;
17518a7d6542SBram Moolenaar 		}
17528a7d6542SBram Moolenaar 		break;
17538a7d6542SBram Moolenaar 
17548a7d6542SBram Moolenaar 	    case ISN_PUSHEXC:
17558a7d6542SBram Moolenaar 		if (current_exception == NULL)
17568a7d6542SBram Moolenaar 		{
17578a7d6542SBram Moolenaar 		    iemsg("Evaluating catch while current_exception is NULL");
17588a7d6542SBram Moolenaar 		    goto failed;
17598a7d6542SBram Moolenaar 		}
1760270d0388SBram Moolenaar 		if (GA_GROW(&ectx.ec_stack, 1) == FAIL)
17618a7d6542SBram Moolenaar 		    goto failed;
17628a7d6542SBram Moolenaar 		tv = STACK_TV_BOT(0);
17638a7d6542SBram Moolenaar 		++ectx.ec_stack.ga_len;
17648a7d6542SBram Moolenaar 		tv->v_type = VAR_STRING;
17658a7d6542SBram Moolenaar 		tv->vval.v_string = vim_strsave(
17668a7d6542SBram Moolenaar 					   (char_u *)current_exception->value);
17678a7d6542SBram Moolenaar 		break;
17688a7d6542SBram Moolenaar 
17698a7d6542SBram Moolenaar 	    case ISN_CATCH:
17708a7d6542SBram Moolenaar 		{
17718a7d6542SBram Moolenaar 		    garray_T	*trystack = &ectx.ec_trystack;
17728a7d6542SBram Moolenaar 
17738a7d6542SBram Moolenaar 		    if (trystack->ga_len > 0)
17748a7d6542SBram Moolenaar 		    {
177520431c9dSBram Moolenaar 			trycmd_T    *trycmd = ((trycmd_T *)trystack->ga_data)
17768a7d6542SBram Moolenaar 							+ trystack->ga_len - 1;
17778a7d6542SBram Moolenaar 			trycmd->tcd_caught = TRUE;
17788a7d6542SBram Moolenaar 		    }
17798a7d6542SBram Moolenaar 		    did_emsg = got_int = did_throw = FALSE;
17808a7d6542SBram Moolenaar 		    catch_exception(current_exception);
17818a7d6542SBram Moolenaar 		}
17828a7d6542SBram Moolenaar 		break;
17838a7d6542SBram Moolenaar 
17848a7d6542SBram Moolenaar 	    // end of ":try" block
17858a7d6542SBram Moolenaar 	    case ISN_ENDTRY:
17868a7d6542SBram Moolenaar 		{
17878a7d6542SBram Moolenaar 		    garray_T	*trystack = &ectx.ec_trystack;
17888a7d6542SBram Moolenaar 
17898a7d6542SBram Moolenaar 		    if (trystack->ga_len > 0)
17908a7d6542SBram Moolenaar 		    {
179120431c9dSBram Moolenaar 			trycmd_T    *trycmd = NULL;
179220431c9dSBram Moolenaar 
17938a7d6542SBram Moolenaar 			--trystack->ga_len;
17948a7d6542SBram Moolenaar 			--trylevel;
179568d130c6SBram Moolenaar 			ectx.ec_in_catch = FALSE;
17968a7d6542SBram Moolenaar 			trycmd = ((trycmd_T *)trystack->ga_data)
17978a7d6542SBram Moolenaar 							    + trystack->ga_len;
1798f575adffSBram Moolenaar 			if (trycmd->tcd_caught && current_exception != NULL)
17998a7d6542SBram Moolenaar 			{
18008a7d6542SBram Moolenaar 			    // discard the exception
18018a7d6542SBram Moolenaar 			    if (caught_stack == current_exception)
18028a7d6542SBram Moolenaar 				caught_stack = caught_stack->caught;
18038a7d6542SBram Moolenaar 			    discard_current_exception();
18048a7d6542SBram Moolenaar 			}
18058a7d6542SBram Moolenaar 
18068a7d6542SBram Moolenaar 			if (trycmd->tcd_return)
1807d032f34aSBram Moolenaar 			    goto func_return;
18088a7d6542SBram Moolenaar 		    }
18098a7d6542SBram Moolenaar 		}
18108a7d6542SBram Moolenaar 		break;
18118a7d6542SBram Moolenaar 
18128a7d6542SBram Moolenaar 	    case ISN_THROW:
18138a7d6542SBram Moolenaar 		--ectx.ec_stack.ga_len;
18148a7d6542SBram Moolenaar 		tv = STACK_TV_BOT(0);
18158a7d6542SBram Moolenaar 		if (throw_exception(tv->vval.v_string, ET_USER, NULL) == FAIL)
18168a7d6542SBram Moolenaar 		{
18178a7d6542SBram Moolenaar 		    vim_free(tv->vval.v_string);
18188a7d6542SBram Moolenaar 		    goto failed;
18198a7d6542SBram Moolenaar 		}
18208a7d6542SBram Moolenaar 		did_throw = TRUE;
18218a7d6542SBram Moolenaar 		break;
18228a7d6542SBram Moolenaar 
18238a7d6542SBram Moolenaar 	    // compare with special values
18248a7d6542SBram Moolenaar 	    case ISN_COMPAREBOOL:
18258a7d6542SBram Moolenaar 	    case ISN_COMPARESPECIAL:
18268a7d6542SBram Moolenaar 		{
18278a7d6542SBram Moolenaar 		    typval_T	*tv1 = STACK_TV_BOT(-2);
18288a7d6542SBram Moolenaar 		    typval_T	*tv2 = STACK_TV_BOT(-1);
18298a7d6542SBram Moolenaar 		    varnumber_T arg1 = tv1->vval.v_number;
18308a7d6542SBram Moolenaar 		    varnumber_T arg2 = tv2->vval.v_number;
18318a7d6542SBram Moolenaar 		    int		res;
18328a7d6542SBram Moolenaar 
18338a7d6542SBram Moolenaar 		    switch (iptr->isn_arg.op.op_type)
18348a7d6542SBram Moolenaar 		    {
18358a7d6542SBram Moolenaar 			case EXPR_EQUAL: res = arg1 == arg2; break;
18368a7d6542SBram Moolenaar 			case EXPR_NEQUAL: res = arg1 != arg2; break;
18378a7d6542SBram Moolenaar 			default: res = 0; break;
18388a7d6542SBram Moolenaar 		    }
18398a7d6542SBram Moolenaar 
18408a7d6542SBram Moolenaar 		    --ectx.ec_stack.ga_len;
18418a7d6542SBram Moolenaar 		    tv1->v_type = VAR_BOOL;
18428a7d6542SBram Moolenaar 		    tv1->vval.v_number = res ? VVAL_TRUE : VVAL_FALSE;
18438a7d6542SBram Moolenaar 		}
18448a7d6542SBram Moolenaar 		break;
18458a7d6542SBram Moolenaar 
18468a7d6542SBram Moolenaar 	    // Operation with two number arguments
18478a7d6542SBram Moolenaar 	    case ISN_OPNR:
18488a7d6542SBram Moolenaar 	    case ISN_COMPARENR:
18498a7d6542SBram Moolenaar 		{
18508a7d6542SBram Moolenaar 		    typval_T	*tv1 = STACK_TV_BOT(-2);
18518a7d6542SBram Moolenaar 		    typval_T	*tv2 = STACK_TV_BOT(-1);
18528a7d6542SBram Moolenaar 		    varnumber_T arg1 = tv1->vval.v_number;
18538a7d6542SBram Moolenaar 		    varnumber_T arg2 = tv2->vval.v_number;
18548a7d6542SBram Moolenaar 		    varnumber_T res;
18558a7d6542SBram Moolenaar 
18568a7d6542SBram Moolenaar 		    switch (iptr->isn_arg.op.op_type)
18578a7d6542SBram Moolenaar 		    {
18588a7d6542SBram Moolenaar 			case EXPR_MULT: res = arg1 * arg2; break;
18598a7d6542SBram Moolenaar 			case EXPR_DIV: res = arg1 / arg2; break;
18608a7d6542SBram Moolenaar 			case EXPR_REM: res = arg1 % arg2; break;
18618a7d6542SBram Moolenaar 			case EXPR_SUB: res = arg1 - arg2; break;
18628a7d6542SBram Moolenaar 			case EXPR_ADD: res = arg1 + arg2; break;
18638a7d6542SBram Moolenaar 
18648a7d6542SBram Moolenaar 			case EXPR_EQUAL: res = arg1 == arg2; break;
18658a7d6542SBram Moolenaar 			case EXPR_NEQUAL: res = arg1 != arg2; break;
18668a7d6542SBram Moolenaar 			case EXPR_GREATER: res = arg1 > arg2; break;
18678a7d6542SBram Moolenaar 			case EXPR_GEQUAL: res = arg1 >= arg2; break;
18688a7d6542SBram Moolenaar 			case EXPR_SMALLER: res = arg1 < arg2; break;
18698a7d6542SBram Moolenaar 			case EXPR_SEQUAL: res = arg1 <= arg2; break;
18708a7d6542SBram Moolenaar 			default: res = 0; break;
18718a7d6542SBram Moolenaar 		    }
18728a7d6542SBram Moolenaar 
18738a7d6542SBram Moolenaar 		    --ectx.ec_stack.ga_len;
18748a7d6542SBram Moolenaar 		    if (iptr->isn_type == ISN_COMPARENR)
18758a7d6542SBram Moolenaar 		    {
18768a7d6542SBram Moolenaar 			tv1->v_type = VAR_BOOL;
18778a7d6542SBram Moolenaar 			tv1->vval.v_number = res ? VVAL_TRUE : VVAL_FALSE;
18788a7d6542SBram Moolenaar 		    }
18798a7d6542SBram Moolenaar 		    else
18808a7d6542SBram Moolenaar 			tv1->vval.v_number = res;
18818a7d6542SBram Moolenaar 		}
18828a7d6542SBram Moolenaar 		break;
18838a7d6542SBram Moolenaar 
18848a7d6542SBram Moolenaar 	    // Computation with two float arguments
18858a7d6542SBram Moolenaar 	    case ISN_OPFLOAT:
18868a7d6542SBram Moolenaar 	    case ISN_COMPAREFLOAT:
1887a5d5953dSBram Moolenaar #ifdef FEAT_FLOAT
18888a7d6542SBram Moolenaar 		{
18898a7d6542SBram Moolenaar 		    typval_T	*tv1 = STACK_TV_BOT(-2);
18908a7d6542SBram Moolenaar 		    typval_T	*tv2 = STACK_TV_BOT(-1);
18918a7d6542SBram Moolenaar 		    float_T	arg1 = tv1->vval.v_float;
18928a7d6542SBram Moolenaar 		    float_T	arg2 = tv2->vval.v_float;
18938a7d6542SBram Moolenaar 		    float_T	res = 0;
18948a7d6542SBram Moolenaar 		    int		cmp = FALSE;
18958a7d6542SBram Moolenaar 
18968a7d6542SBram Moolenaar 		    switch (iptr->isn_arg.op.op_type)
18978a7d6542SBram Moolenaar 		    {
18988a7d6542SBram Moolenaar 			case EXPR_MULT: res = arg1 * arg2; break;
18998a7d6542SBram Moolenaar 			case EXPR_DIV: res = arg1 / arg2; break;
19008a7d6542SBram Moolenaar 			case EXPR_SUB: res = arg1 - arg2; break;
19018a7d6542SBram Moolenaar 			case EXPR_ADD: res = arg1 + arg2; break;
19028a7d6542SBram Moolenaar 
19038a7d6542SBram Moolenaar 			case EXPR_EQUAL: cmp = arg1 == arg2; break;
19048a7d6542SBram Moolenaar 			case EXPR_NEQUAL: cmp = arg1 != arg2; break;
19058a7d6542SBram Moolenaar 			case EXPR_GREATER: cmp = arg1 > arg2; break;
19068a7d6542SBram Moolenaar 			case EXPR_GEQUAL: cmp = arg1 >= arg2; break;
19078a7d6542SBram Moolenaar 			case EXPR_SMALLER: cmp = arg1 < arg2; break;
19088a7d6542SBram Moolenaar 			case EXPR_SEQUAL: cmp = arg1 <= arg2; break;
19098a7d6542SBram Moolenaar 			default: cmp = 0; break;
19108a7d6542SBram Moolenaar 		    }
19118a7d6542SBram Moolenaar 		    --ectx.ec_stack.ga_len;
19128a7d6542SBram Moolenaar 		    if (iptr->isn_type == ISN_COMPAREFLOAT)
19138a7d6542SBram Moolenaar 		    {
19148a7d6542SBram Moolenaar 			tv1->v_type = VAR_BOOL;
19158a7d6542SBram Moolenaar 			tv1->vval.v_number = cmp ? VVAL_TRUE : VVAL_FALSE;
19168a7d6542SBram Moolenaar 		    }
19178a7d6542SBram Moolenaar 		    else
19188a7d6542SBram Moolenaar 			tv1->vval.v_float = res;
19198a7d6542SBram Moolenaar 		}
1920a5d5953dSBram Moolenaar #endif
19218a7d6542SBram Moolenaar 		break;
19228a7d6542SBram Moolenaar 
19238a7d6542SBram Moolenaar 	    case ISN_COMPARELIST:
19248a7d6542SBram Moolenaar 		{
19258a7d6542SBram Moolenaar 		    typval_T	*tv1 = STACK_TV_BOT(-2);
19268a7d6542SBram Moolenaar 		    typval_T	*tv2 = STACK_TV_BOT(-1);
19278a7d6542SBram Moolenaar 		    list_T	*arg1 = tv1->vval.v_list;
19288a7d6542SBram Moolenaar 		    list_T	*arg2 = tv2->vval.v_list;
19298a7d6542SBram Moolenaar 		    int		cmp = FALSE;
19308a7d6542SBram Moolenaar 		    int		ic = iptr->isn_arg.op.op_ic;
19318a7d6542SBram Moolenaar 
19328a7d6542SBram Moolenaar 		    switch (iptr->isn_arg.op.op_type)
19338a7d6542SBram Moolenaar 		    {
19348a7d6542SBram Moolenaar 			case EXPR_EQUAL: cmp =
19358a7d6542SBram Moolenaar 				      list_equal(arg1, arg2, ic, FALSE); break;
19368a7d6542SBram Moolenaar 			case EXPR_NEQUAL: cmp =
19378a7d6542SBram Moolenaar 				     !list_equal(arg1, arg2, ic, FALSE); break;
19388a7d6542SBram Moolenaar 			case EXPR_IS: cmp = arg1 == arg2; break;
19398a7d6542SBram Moolenaar 			case EXPR_ISNOT: cmp = arg1 != arg2; break;
19408a7d6542SBram Moolenaar 			default: cmp = 0; break;
19418a7d6542SBram Moolenaar 		    }
19428a7d6542SBram Moolenaar 		    --ectx.ec_stack.ga_len;
19438a7d6542SBram Moolenaar 		    clear_tv(tv1);
19448a7d6542SBram Moolenaar 		    clear_tv(tv2);
19458a7d6542SBram Moolenaar 		    tv1->v_type = VAR_BOOL;
19468a7d6542SBram Moolenaar 		    tv1->vval.v_number = cmp ? VVAL_TRUE : VVAL_FALSE;
19478a7d6542SBram Moolenaar 		}
19488a7d6542SBram Moolenaar 		break;
19498a7d6542SBram Moolenaar 
19508a7d6542SBram Moolenaar 	    case ISN_COMPAREBLOB:
19518a7d6542SBram Moolenaar 		{
19528a7d6542SBram Moolenaar 		    typval_T	*tv1 = STACK_TV_BOT(-2);
19538a7d6542SBram Moolenaar 		    typval_T	*tv2 = STACK_TV_BOT(-1);
19548a7d6542SBram Moolenaar 		    blob_T	*arg1 = tv1->vval.v_blob;
19558a7d6542SBram Moolenaar 		    blob_T	*arg2 = tv2->vval.v_blob;
19568a7d6542SBram Moolenaar 		    int		cmp = FALSE;
19578a7d6542SBram Moolenaar 
19588a7d6542SBram Moolenaar 		    switch (iptr->isn_arg.op.op_type)
19598a7d6542SBram Moolenaar 		    {
19608a7d6542SBram Moolenaar 			case EXPR_EQUAL: cmp = blob_equal(arg1, arg2); break;
19618a7d6542SBram Moolenaar 			case EXPR_NEQUAL: cmp = !blob_equal(arg1, arg2); break;
19628a7d6542SBram Moolenaar 			case EXPR_IS: cmp = arg1 == arg2; break;
19638a7d6542SBram Moolenaar 			case EXPR_ISNOT: cmp = arg1 != arg2; break;
19648a7d6542SBram Moolenaar 			default: cmp = 0; break;
19658a7d6542SBram Moolenaar 		    }
19668a7d6542SBram Moolenaar 		    --ectx.ec_stack.ga_len;
19678a7d6542SBram Moolenaar 		    clear_tv(tv1);
19688a7d6542SBram Moolenaar 		    clear_tv(tv2);
19698a7d6542SBram Moolenaar 		    tv1->v_type = VAR_BOOL;
19708a7d6542SBram Moolenaar 		    tv1->vval.v_number = cmp ? VVAL_TRUE : VVAL_FALSE;
19718a7d6542SBram Moolenaar 		}
19728a7d6542SBram Moolenaar 		break;
19738a7d6542SBram Moolenaar 
19748a7d6542SBram Moolenaar 		// TODO: handle separately
19758a7d6542SBram Moolenaar 	    case ISN_COMPARESTRING:
19768a7d6542SBram Moolenaar 	    case ISN_COMPAREDICT:
19778a7d6542SBram Moolenaar 	    case ISN_COMPAREFUNC:
19788a7d6542SBram Moolenaar 	    case ISN_COMPAREANY:
19798a7d6542SBram Moolenaar 		{
19808a7d6542SBram Moolenaar 		    typval_T	*tv1 = STACK_TV_BOT(-2);
19818a7d6542SBram Moolenaar 		    typval_T	*tv2 = STACK_TV_BOT(-1);
19828a7d6542SBram Moolenaar 		    exptype_T	exptype = iptr->isn_arg.op.op_type;
19838a7d6542SBram Moolenaar 		    int		ic = iptr->isn_arg.op.op_ic;
19848a7d6542SBram Moolenaar 
19858a7d6542SBram Moolenaar 		    typval_compare(tv1, tv2, exptype, ic);
19868a7d6542SBram Moolenaar 		    clear_tv(tv2);
19878a7d6542SBram Moolenaar 		    tv1->v_type = VAR_BOOL;
19888a7d6542SBram Moolenaar 		    tv1->vval.v_number = tv1->vval.v_number
19898a7d6542SBram Moolenaar 						      ? VVAL_TRUE : VVAL_FALSE;
19908a7d6542SBram Moolenaar 		    --ectx.ec_stack.ga_len;
19918a7d6542SBram Moolenaar 		}
19928a7d6542SBram Moolenaar 		break;
19938a7d6542SBram Moolenaar 
19948a7d6542SBram Moolenaar 	    case ISN_ADDLIST:
19958a7d6542SBram Moolenaar 	    case ISN_ADDBLOB:
19968a7d6542SBram Moolenaar 		{
19978a7d6542SBram Moolenaar 		    typval_T *tv1 = STACK_TV_BOT(-2);
19988a7d6542SBram Moolenaar 		    typval_T *tv2 = STACK_TV_BOT(-1);
19998a7d6542SBram Moolenaar 
20008a7d6542SBram Moolenaar 		    if (iptr->isn_type == ISN_ADDLIST)
20018a7d6542SBram Moolenaar 			eval_addlist(tv1, tv2);
20028a7d6542SBram Moolenaar 		    else
20038a7d6542SBram Moolenaar 			eval_addblob(tv1, tv2);
20048a7d6542SBram Moolenaar 		    clear_tv(tv2);
20058a7d6542SBram Moolenaar 		    --ectx.ec_stack.ga_len;
20068a7d6542SBram Moolenaar 		}
20078a7d6542SBram Moolenaar 		break;
20088a7d6542SBram Moolenaar 
20098a7d6542SBram Moolenaar 	    // Computation with two arguments of unknown type
20108a7d6542SBram Moolenaar 	    case ISN_OPANY:
20118a7d6542SBram Moolenaar 		{
20128a7d6542SBram Moolenaar 		    typval_T	*tv1 = STACK_TV_BOT(-2);
20138a7d6542SBram Moolenaar 		    typval_T	*tv2 = STACK_TV_BOT(-1);
20148a7d6542SBram Moolenaar 		    varnumber_T	n1, n2;
20158a7d6542SBram Moolenaar #ifdef FEAT_FLOAT
20168a7d6542SBram Moolenaar 		    float_T	f1 = 0, f2 = 0;
20178a7d6542SBram Moolenaar #endif
20188a7d6542SBram Moolenaar 		    int		error = FALSE;
20198a7d6542SBram Moolenaar 
20208a7d6542SBram Moolenaar 		    if (iptr->isn_arg.op.op_type == EXPR_ADD)
20218a7d6542SBram Moolenaar 		    {
20228a7d6542SBram Moolenaar 			if (tv1->v_type == VAR_LIST && tv2->v_type == VAR_LIST)
20238a7d6542SBram Moolenaar 			{
20248a7d6542SBram Moolenaar 			    eval_addlist(tv1, tv2);
20258a7d6542SBram Moolenaar 			    clear_tv(tv2);
20268a7d6542SBram Moolenaar 			    --ectx.ec_stack.ga_len;
20278a7d6542SBram Moolenaar 			    break;
20288a7d6542SBram Moolenaar 			}
20298a7d6542SBram Moolenaar 			else if (tv1->v_type == VAR_BLOB
20308a7d6542SBram Moolenaar 						    && tv2->v_type == VAR_BLOB)
20318a7d6542SBram Moolenaar 			{
20328a7d6542SBram Moolenaar 			    eval_addblob(tv1, tv2);
20338a7d6542SBram Moolenaar 			    clear_tv(tv2);
20348a7d6542SBram Moolenaar 			    --ectx.ec_stack.ga_len;
20358a7d6542SBram Moolenaar 			    break;
20368a7d6542SBram Moolenaar 			}
20378a7d6542SBram Moolenaar 		    }
20388a7d6542SBram Moolenaar #ifdef FEAT_FLOAT
20398a7d6542SBram Moolenaar 		    if (tv1->v_type == VAR_FLOAT)
20408a7d6542SBram Moolenaar 		    {
20418a7d6542SBram Moolenaar 			f1 = tv1->vval.v_float;
20428a7d6542SBram Moolenaar 			n1 = 0;
20438a7d6542SBram Moolenaar 		    }
20448a7d6542SBram Moolenaar 		    else
20458a7d6542SBram Moolenaar #endif
20468a7d6542SBram Moolenaar 		    {
20478a7d6542SBram Moolenaar 			n1 = tv_get_number_chk(tv1, &error);
20488a7d6542SBram Moolenaar 			if (error)
2049d032f34aSBram Moolenaar 			    goto on_error;
20508a7d6542SBram Moolenaar #ifdef FEAT_FLOAT
20518a7d6542SBram Moolenaar 			if (tv2->v_type == VAR_FLOAT)
20528a7d6542SBram Moolenaar 			    f1 = n1;
20538a7d6542SBram Moolenaar #endif
20548a7d6542SBram Moolenaar 		    }
20558a7d6542SBram Moolenaar #ifdef FEAT_FLOAT
20568a7d6542SBram Moolenaar 		    if (tv2->v_type == VAR_FLOAT)
20578a7d6542SBram Moolenaar 		    {
20588a7d6542SBram Moolenaar 			f2 = tv2->vval.v_float;
20598a7d6542SBram Moolenaar 			n2 = 0;
20608a7d6542SBram Moolenaar 		    }
20618a7d6542SBram Moolenaar 		    else
20628a7d6542SBram Moolenaar #endif
20638a7d6542SBram Moolenaar 		    {
20648a7d6542SBram Moolenaar 			n2 = tv_get_number_chk(tv2, &error);
20658a7d6542SBram Moolenaar 			if (error)
2066d032f34aSBram Moolenaar 			    goto on_error;
20678a7d6542SBram Moolenaar #ifdef FEAT_FLOAT
20688a7d6542SBram Moolenaar 			if (tv1->v_type == VAR_FLOAT)
20698a7d6542SBram Moolenaar 			    f2 = n2;
20708a7d6542SBram Moolenaar #endif
20718a7d6542SBram Moolenaar 		    }
20728a7d6542SBram Moolenaar #ifdef FEAT_FLOAT
20738a7d6542SBram Moolenaar 		    // if there is a float on either side the result is a float
20748a7d6542SBram Moolenaar 		    if (tv1->v_type == VAR_FLOAT || tv2->v_type == VAR_FLOAT)
20758a7d6542SBram Moolenaar 		    {
20768a7d6542SBram Moolenaar 			switch (iptr->isn_arg.op.op_type)
20778a7d6542SBram Moolenaar 			{
20788a7d6542SBram Moolenaar 			    case EXPR_MULT: f1 = f1 * f2; break;
20798a7d6542SBram Moolenaar 			    case EXPR_DIV:  f1 = f1 / f2; break;
20808a7d6542SBram Moolenaar 			    case EXPR_SUB:  f1 = f1 - f2; break;
20818a7d6542SBram Moolenaar 			    case EXPR_ADD:  f1 = f1 + f2; break;
208268d130c6SBram Moolenaar 			    default: emsg(_(e_modulus));
2083f0b9f43cSBram Moolenaar 				     goto on_error;
20848a7d6542SBram Moolenaar 			}
20858a7d6542SBram Moolenaar 			clear_tv(tv1);
20868a7d6542SBram Moolenaar 			clear_tv(tv2);
20878a7d6542SBram Moolenaar 			tv1->v_type = VAR_FLOAT;
20888a7d6542SBram Moolenaar 			tv1->vval.v_float = f1;
20898a7d6542SBram Moolenaar 			--ectx.ec_stack.ga_len;
20908a7d6542SBram Moolenaar 		    }
20918a7d6542SBram Moolenaar 		    else
20928a7d6542SBram Moolenaar #endif
20938a7d6542SBram Moolenaar 		    {
20948a7d6542SBram Moolenaar 			switch (iptr->isn_arg.op.op_type)
20958a7d6542SBram Moolenaar 			{
20968a7d6542SBram Moolenaar 			    case EXPR_MULT: n1 = n1 * n2; break;
20978a7d6542SBram Moolenaar 			    case EXPR_DIV:  n1 = num_divide(n1, n2); break;
20988a7d6542SBram Moolenaar 			    case EXPR_SUB:  n1 = n1 - n2; break;
20998a7d6542SBram Moolenaar 			    case EXPR_ADD:  n1 = n1 + n2; break;
21008a7d6542SBram Moolenaar 			    default:	    n1 = num_modulus(n1, n2); break;
21018a7d6542SBram Moolenaar 			}
21028a7d6542SBram Moolenaar 			clear_tv(tv1);
21038a7d6542SBram Moolenaar 			clear_tv(tv2);
21048a7d6542SBram Moolenaar 			tv1->v_type = VAR_NUMBER;
21058a7d6542SBram Moolenaar 			tv1->vval.v_number = n1;
21068a7d6542SBram Moolenaar 			--ectx.ec_stack.ga_len;
21078a7d6542SBram Moolenaar 		    }
21088a7d6542SBram Moolenaar 		}
21098a7d6542SBram Moolenaar 		break;
21108a7d6542SBram Moolenaar 
21118a7d6542SBram Moolenaar 	    case ISN_CONCAT:
21128a7d6542SBram Moolenaar 		{
21138a7d6542SBram Moolenaar 		    char_u *str1 = STACK_TV_BOT(-2)->vval.v_string;
21148a7d6542SBram Moolenaar 		    char_u *str2 = STACK_TV_BOT(-1)->vval.v_string;
21158a7d6542SBram Moolenaar 		    char_u *res;
21168a7d6542SBram Moolenaar 
21178a7d6542SBram Moolenaar 		    res = concat_str(str1, str2);
21188a7d6542SBram Moolenaar 		    clear_tv(STACK_TV_BOT(-2));
21198a7d6542SBram Moolenaar 		    clear_tv(STACK_TV_BOT(-1));
21208a7d6542SBram Moolenaar 		    --ectx.ec_stack.ga_len;
21218a7d6542SBram Moolenaar 		    STACK_TV_BOT(-1)->vval.v_string = res;
21228a7d6542SBram Moolenaar 		}
21238a7d6542SBram Moolenaar 		break;
21248a7d6542SBram Moolenaar 
21258a7d6542SBram Moolenaar 	    case ISN_INDEX:
21268a7d6542SBram Moolenaar 		{
21278a7d6542SBram Moolenaar 		    list_T	*list;
21288a7d6542SBram Moolenaar 		    varnumber_T	n;
21298a7d6542SBram Moolenaar 		    listitem_T	*li;
2130435d8978SBram Moolenaar 		    typval_T	temp_tv;
21318a7d6542SBram Moolenaar 
21328a7d6542SBram Moolenaar 		    // list index: list is at stack-2, index at stack-1
21338a7d6542SBram Moolenaar 		    tv = STACK_TV_BOT(-2);
21348a7d6542SBram Moolenaar 		    if (tv->v_type != VAR_LIST)
21358a7d6542SBram Moolenaar 		    {
21368a7d6542SBram Moolenaar 			emsg(_(e_listreq));
2137f0b9f43cSBram Moolenaar 			goto on_error;
21388a7d6542SBram Moolenaar 		    }
21398a7d6542SBram Moolenaar 		    list = tv->vval.v_list;
21408a7d6542SBram Moolenaar 
21418a7d6542SBram Moolenaar 		    tv = STACK_TV_BOT(-1);
21428a7d6542SBram Moolenaar 		    if (tv->v_type != VAR_NUMBER)
21438a7d6542SBram Moolenaar 		    {
21448a7d6542SBram Moolenaar 			emsg(_(e_number_exp));
2145f0b9f43cSBram Moolenaar 			goto on_error;
21468a7d6542SBram Moolenaar 		    }
21478a7d6542SBram Moolenaar 		    n = tv->vval.v_number;
21488a7d6542SBram Moolenaar 		    clear_tv(tv);
21498a7d6542SBram Moolenaar 		    if ((li = list_find(list, n)) == NULL)
21508a7d6542SBram Moolenaar 		    {
21518a7d6542SBram Moolenaar 			semsg(_(e_listidx), n);
2152f0b9f43cSBram Moolenaar 			goto on_error;
21538a7d6542SBram Moolenaar 		    }
21548a7d6542SBram Moolenaar 		    --ectx.ec_stack.ga_len;
2155435d8978SBram Moolenaar 		    // Clear the list after getting the item, to avoid that it
215668d130c6SBram Moolenaar 		    // makes the item invalid.
2157435d8978SBram Moolenaar 		    tv = STACK_TV_BOT(-1);
2158435d8978SBram Moolenaar 		    temp_tv = *tv;
2159435d8978SBram Moolenaar 		    copy_tv(&li->li_tv, tv);
2160435d8978SBram Moolenaar 		    clear_tv(&temp_tv);
21618a7d6542SBram Moolenaar 		}
21628a7d6542SBram Moolenaar 		break;
21638a7d6542SBram Moolenaar 
21649af78769SBram Moolenaar 	    case ISN_SLICE:
21659af78769SBram Moolenaar 		{
21669af78769SBram Moolenaar 		    list_T	*list;
21679af78769SBram Moolenaar 		    int		count = iptr->isn_arg.number;
21689af78769SBram Moolenaar 
2169c5b1c20bSBram Moolenaar 		    // type will have been checked to be a list
21709af78769SBram Moolenaar 		    tv = STACK_TV_BOT(-1);
21719af78769SBram Moolenaar 		    list = tv->vval.v_list;
21729af78769SBram Moolenaar 
21739af78769SBram Moolenaar 		    // no error for short list, expect it to be checked earlier
21749af78769SBram Moolenaar 		    if (list != NULL && list->lv_len >= count)
21759af78769SBram Moolenaar 		    {
21769af78769SBram Moolenaar 			list_T	*newlist = list_slice(list,
21779af78769SBram Moolenaar 						      count, list->lv_len - 1);
21789af78769SBram Moolenaar 
21799af78769SBram Moolenaar 			if (newlist != NULL)
21809af78769SBram Moolenaar 			{
21819af78769SBram Moolenaar 			    list_unref(list);
21829af78769SBram Moolenaar 			    tv->vval.v_list = newlist;
21839af78769SBram Moolenaar 			    ++newlist->lv_refcount;
21849af78769SBram Moolenaar 			}
21859af78769SBram Moolenaar 		    }
21869af78769SBram Moolenaar 		}
21879af78769SBram Moolenaar 		break;
21889af78769SBram Moolenaar 
218947a519a9SBram Moolenaar 	    case ISN_GETITEM:
219047a519a9SBram Moolenaar 		{
219147a519a9SBram Moolenaar 		    listitem_T	*li;
219247a519a9SBram Moolenaar 		    int		index = iptr->isn_arg.number;
219347a519a9SBram Moolenaar 
2194c785b9a7SBram Moolenaar 		    // Get list item: list is at stack-1, push item.
2195c785b9a7SBram Moolenaar 		    // List type and length is checked for when compiling.
219647a519a9SBram Moolenaar 		    tv = STACK_TV_BOT(-1);
2197c785b9a7SBram Moolenaar 		    li = list_find(tv->vval.v_list, index);
219847a519a9SBram Moolenaar 
219947a519a9SBram Moolenaar 		    if (GA_GROW(&ectx.ec_stack, 1) == FAIL)
220047a519a9SBram Moolenaar 			goto failed;
220147a519a9SBram Moolenaar 		    ++ectx.ec_stack.ga_len;
220247a519a9SBram Moolenaar 		    copy_tv(&li->li_tv, STACK_TV_BOT(-1));
220347a519a9SBram Moolenaar 		}
220447a519a9SBram Moolenaar 		break;
220547a519a9SBram Moolenaar 
22068a7d6542SBram Moolenaar 	    case ISN_MEMBER:
22078a7d6542SBram Moolenaar 		{
22088a7d6542SBram Moolenaar 		    dict_T	*dict;
22091cc2a94fSBram Moolenaar 		    char_u	*key;
22101cc2a94fSBram Moolenaar 		    dictitem_T	*di;
221150788ef3SBram Moolenaar 		    typval_T	temp_tv;
22121cc2a94fSBram Moolenaar 
22131cc2a94fSBram Moolenaar 		    // dict member: dict is at stack-2, key at stack-1
22141cc2a94fSBram Moolenaar 		    tv = STACK_TV_BOT(-2);
22154dac32caSBram Moolenaar 		    // no need to check for VAR_DICT, CHECKTYPE will check.
22161cc2a94fSBram Moolenaar 		    dict = tv->vval.v_dict;
22171cc2a94fSBram Moolenaar 
22181cc2a94fSBram Moolenaar 		    tv = STACK_TV_BOT(-1);
22194dac32caSBram Moolenaar 		    // no need to check for VAR_STRING, 2STRING will check.
22201cc2a94fSBram Moolenaar 		    key = tv->vval.v_string;
22214dac32caSBram Moolenaar 
22221cc2a94fSBram Moolenaar 		    if ((di = dict_find(dict, key, -1)) == NULL)
22231cc2a94fSBram Moolenaar 		    {
22241cc2a94fSBram Moolenaar 			semsg(_(e_dictkey), key);
2225f0b9f43cSBram Moolenaar 			goto on_error;
22261cc2a94fSBram Moolenaar 		    }
22271cc2a94fSBram Moolenaar 		    clear_tv(tv);
222850788ef3SBram Moolenaar 		    --ectx.ec_stack.ga_len;
222950788ef3SBram Moolenaar 		    // Clear the dict after getting the item, to avoid that it
223050788ef3SBram Moolenaar 		    // make the item invalid.
223150788ef3SBram Moolenaar 		    tv = STACK_TV_BOT(-1);
223250788ef3SBram Moolenaar 		    temp_tv = *tv;
223350788ef3SBram Moolenaar 		    copy_tv(&di->di_tv, tv);
223450788ef3SBram Moolenaar 		    clear_tv(&temp_tv);
22351cc2a94fSBram Moolenaar 		}
22361cc2a94fSBram Moolenaar 		break;
22371cc2a94fSBram Moolenaar 
22381cc2a94fSBram Moolenaar 	    // dict member with string key
22391cc2a94fSBram Moolenaar 	    case ISN_STRINGMEMBER:
22401cc2a94fSBram Moolenaar 		{
22411cc2a94fSBram Moolenaar 		    dict_T	*dict;
22428a7d6542SBram Moolenaar 		    dictitem_T	*di;
2243fb9d5c51SBram Moolenaar 		    typval_T	temp_tv;
22448a7d6542SBram Moolenaar 
22458a7d6542SBram Moolenaar 		    tv = STACK_TV_BOT(-1);
22468a7d6542SBram Moolenaar 		    if (tv->v_type != VAR_DICT || tv->vval.v_dict == NULL)
22478a7d6542SBram Moolenaar 		    {
22488a7d6542SBram Moolenaar 			emsg(_(e_dictreq));
2249d032f34aSBram Moolenaar 			goto on_error;
22508a7d6542SBram Moolenaar 		    }
22518a7d6542SBram Moolenaar 		    dict = tv->vval.v_dict;
22528a7d6542SBram Moolenaar 
22538a7d6542SBram Moolenaar 		    if ((di = dict_find(dict, iptr->isn_arg.string, -1))
22548a7d6542SBram Moolenaar 								       == NULL)
22558a7d6542SBram Moolenaar 		    {
22568a7d6542SBram Moolenaar 			semsg(_(e_dictkey), iptr->isn_arg.string);
2257d032f34aSBram Moolenaar 			goto on_error;
22588a7d6542SBram Moolenaar 		    }
2259fb9d5c51SBram Moolenaar 		    // Clear the dict after getting the item, to avoid that it
2260fb9d5c51SBram Moolenaar 		    // make the item invalid.
2261fb9d5c51SBram Moolenaar 		    temp_tv = *tv;
22628a7d6542SBram Moolenaar 		    copy_tv(&di->di_tv, tv);
2263fb9d5c51SBram Moolenaar 		    clear_tv(&temp_tv);
22648a7d6542SBram Moolenaar 		}
22658a7d6542SBram Moolenaar 		break;
22668a7d6542SBram Moolenaar 
22678a7d6542SBram Moolenaar 	    case ISN_NEGATENR:
22688a7d6542SBram Moolenaar 		tv = STACK_TV_BOT(-1);
2269c58164c5SBram Moolenaar 		if (tv->v_type != VAR_NUMBER
2270c58164c5SBram Moolenaar #ifdef FEAT_FLOAT
2271c58164c5SBram Moolenaar 			&& tv->v_type != VAR_FLOAT
2272c58164c5SBram Moolenaar #endif
2273c58164c5SBram Moolenaar 			)
2274c58164c5SBram Moolenaar 		{
2275c58164c5SBram Moolenaar 		    emsg(_(e_number_exp));
2276f0b9f43cSBram Moolenaar 		    goto on_error;
2277c58164c5SBram Moolenaar 		}
2278c58164c5SBram Moolenaar #ifdef FEAT_FLOAT
2279c58164c5SBram Moolenaar 		if (tv->v_type == VAR_FLOAT)
2280c58164c5SBram Moolenaar 		    tv->vval.v_float = -tv->vval.v_float;
2281c58164c5SBram Moolenaar 		else
2282c58164c5SBram Moolenaar #endif
22838a7d6542SBram Moolenaar 		    tv->vval.v_number = -tv->vval.v_number;
22848a7d6542SBram Moolenaar 		break;
22858a7d6542SBram Moolenaar 
22868a7d6542SBram Moolenaar 	    case ISN_CHECKNR:
22878a7d6542SBram Moolenaar 		{
22888a7d6542SBram Moolenaar 		    int		error = FALSE;
22898a7d6542SBram Moolenaar 
22908a7d6542SBram Moolenaar 		    tv = STACK_TV_BOT(-1);
22918a7d6542SBram Moolenaar 		    if (check_not_string(tv) == FAIL)
2292f0b9f43cSBram Moolenaar 			goto on_error;
22938a7d6542SBram Moolenaar 		    (void)tv_get_number_chk(tv, &error);
22948a7d6542SBram Moolenaar 		    if (error)
2295f0b9f43cSBram Moolenaar 			goto on_error;
22968a7d6542SBram Moolenaar 		}
22978a7d6542SBram Moolenaar 		break;
22988a7d6542SBram Moolenaar 
22998a7d6542SBram Moolenaar 	    case ISN_CHECKTYPE:
23008a7d6542SBram Moolenaar 		{
23018a7d6542SBram Moolenaar 		    checktype_T *ct = &iptr->isn_arg.type;
23028a7d6542SBram Moolenaar 
23038a7d6542SBram Moolenaar 		    tv = STACK_TV_BOT(ct->ct_off);
2304c8cd2b34SBram Moolenaar 		    // TODO: better type comparison
2305c8cd2b34SBram Moolenaar 		    if (tv->v_type != ct->ct_type
2306c8cd2b34SBram Moolenaar 			    && !((tv->v_type == VAR_PARTIAL
2307c8cd2b34SBram Moolenaar 						   && ct->ct_type == VAR_FUNC)
2308c8cd2b34SBram Moolenaar 				|| (tv->v_type == VAR_FUNC
2309c8cd2b34SBram Moolenaar 					       && ct->ct_type == VAR_PARTIAL)))
23108a7d6542SBram Moolenaar 		    {
23118a7d6542SBram Moolenaar 			semsg(_("E1029: Expected %s but got %s"),
23128a7d6542SBram Moolenaar 				    vartype_name(ct->ct_type),
23138a7d6542SBram Moolenaar 				    vartype_name(tv->v_type));
2314f0b9f43cSBram Moolenaar 			goto on_error;
23158a7d6542SBram Moolenaar 		    }
23168a7d6542SBram Moolenaar 		}
23178a7d6542SBram Moolenaar 		break;
23188a7d6542SBram Moolenaar 
23199af78769SBram Moolenaar 	    case ISN_CHECKLEN:
23209af78769SBram Moolenaar 		{
23219af78769SBram Moolenaar 		    int	    min_len = iptr->isn_arg.checklen.cl_min_len;
23229af78769SBram Moolenaar 		    list_T  *list = NULL;
23239af78769SBram Moolenaar 
23249af78769SBram Moolenaar 		    tv = STACK_TV_BOT(-1);
23259af78769SBram Moolenaar 		    if (tv->v_type == VAR_LIST)
23269af78769SBram Moolenaar 			    list = tv->vval.v_list;
23279af78769SBram Moolenaar 		    if (list == NULL || list->lv_len < min_len
23289af78769SBram Moolenaar 			    || (list->lv_len > min_len
23299af78769SBram Moolenaar 					&& !iptr->isn_arg.checklen.cl_more_OK))
23309af78769SBram Moolenaar 		    {
23319af78769SBram Moolenaar 			semsg(_("E1093: Expected %d items but got %d"),
23329af78769SBram Moolenaar 				     min_len, list == NULL ? 0 : list->lv_len);
2333f0b9f43cSBram Moolenaar 			goto on_error;
23349af78769SBram Moolenaar 		    }
23359af78769SBram Moolenaar 		}
23369af78769SBram Moolenaar 		break;
23379af78769SBram Moolenaar 
23388a7d6542SBram Moolenaar 	    case ISN_2BOOL:
23398a7d6542SBram Moolenaar 		{
23408a7d6542SBram Moolenaar 		    int n;
23418a7d6542SBram Moolenaar 
23428a7d6542SBram Moolenaar 		    tv = STACK_TV_BOT(-1);
23438a7d6542SBram Moolenaar 		    n = tv2bool(tv);
23448a7d6542SBram Moolenaar 		    if (iptr->isn_arg.number)  // invert
23458a7d6542SBram Moolenaar 			n = !n;
23468a7d6542SBram Moolenaar 		    clear_tv(tv);
23478a7d6542SBram Moolenaar 		    tv->v_type = VAR_BOOL;
23488a7d6542SBram Moolenaar 		    tv->vval.v_number = n ? VVAL_TRUE : VVAL_FALSE;
23498a7d6542SBram Moolenaar 		}
23508a7d6542SBram Moolenaar 		break;
23518a7d6542SBram Moolenaar 
23528a7d6542SBram Moolenaar 	    case ISN_2STRING:
23538a7d6542SBram Moolenaar 		{
23548a7d6542SBram Moolenaar 		    char_u *str;
23558a7d6542SBram Moolenaar 
23568a7d6542SBram Moolenaar 		    tv = STACK_TV_BOT(iptr->isn_arg.number);
23578a7d6542SBram Moolenaar 		    if (tv->v_type != VAR_STRING)
23588a7d6542SBram Moolenaar 		    {
23598a7d6542SBram Moolenaar 			str = typval_tostring(tv);
23608a7d6542SBram Moolenaar 			clear_tv(tv);
23618a7d6542SBram Moolenaar 			tv->v_type = VAR_STRING;
23628a7d6542SBram Moolenaar 			tv->vval.v_string = str;
23638a7d6542SBram Moolenaar 		    }
23648a7d6542SBram Moolenaar 		}
23658a7d6542SBram Moolenaar 		break;
23668a7d6542SBram Moolenaar 
2367389df259SBram Moolenaar 	    case ISN_SHUFFLE:
2368389df259SBram Moolenaar 		{
2369389df259SBram Moolenaar 		    typval_T	    tmp_tv;
2370389df259SBram Moolenaar 		    int		    item = iptr->isn_arg.shuffle.shfl_item;
2371389df259SBram Moolenaar 		    int		    up = iptr->isn_arg.shuffle.shfl_up;
2372389df259SBram Moolenaar 
2373389df259SBram Moolenaar 		    tmp_tv = *STACK_TV_BOT(-item);
2374389df259SBram Moolenaar 		    for ( ; up > 0 && item > 1; --up)
2375389df259SBram Moolenaar 		    {
2376389df259SBram Moolenaar 			*STACK_TV_BOT(-item) = *STACK_TV_BOT(-item + 1);
2377389df259SBram Moolenaar 			--item;
2378389df259SBram Moolenaar 		    }
2379389df259SBram Moolenaar 		    *STACK_TV_BOT(-item) = tmp_tv;
2380389df259SBram Moolenaar 		}
2381389df259SBram Moolenaar 		break;
2382389df259SBram Moolenaar 
23838a7d6542SBram Moolenaar 	    case ISN_DROP:
23848a7d6542SBram Moolenaar 		--ectx.ec_stack.ga_len;
23858a7d6542SBram Moolenaar 		clear_tv(STACK_TV_BOT(0));
23868a7d6542SBram Moolenaar 		break;
23878a7d6542SBram Moolenaar 	}
2388f0b9f43cSBram Moolenaar 	continue;
2389f0b9f43cSBram Moolenaar 
2390d032f34aSBram Moolenaar func_return:
2391d032f34aSBram Moolenaar 	// Restore previous function. If the frame pointer is zero then there
2392d032f34aSBram Moolenaar 	// is none and we are done.
2393d032f34aSBram Moolenaar 	if (ectx.ec_frame_idx == initial_frame_idx)
2394d032f34aSBram Moolenaar 	{
2395d032f34aSBram Moolenaar 	    if (handle_closure_in_use(&ectx, FALSE) == FAIL)
2396d032f34aSBram Moolenaar 		// only fails when out of memory
2397d032f34aSBram Moolenaar 		goto failed;
2398d032f34aSBram Moolenaar 	    goto done;
2399d032f34aSBram Moolenaar 	}
2400d032f34aSBram Moolenaar 	if (func_return(&ectx) == FAIL)
2401d032f34aSBram Moolenaar 	    // only fails when out of memory
2402d032f34aSBram Moolenaar 	    goto failed;
2403d032f34aSBram Moolenaar 
2404f0b9f43cSBram Moolenaar on_error:
2405f0b9f43cSBram Moolenaar 	if (trylevel == 0)
2406f0b9f43cSBram Moolenaar 	    goto failed;
24078a7d6542SBram Moolenaar     }
24088a7d6542SBram Moolenaar 
24098a7d6542SBram Moolenaar done:
24108a7d6542SBram Moolenaar     // function finished, get result from the stack.
24118a7d6542SBram Moolenaar     tv = STACK_TV_BOT(-1);
24128a7d6542SBram Moolenaar     *rettv = *tv;
24138a7d6542SBram Moolenaar     tv->v_type = VAR_UNKNOWN;
24148a7d6542SBram Moolenaar     ret = OK;
24158a7d6542SBram Moolenaar 
24168a7d6542SBram Moolenaar failed:
24177eeefd4aSBram Moolenaar     // When failed need to unwind the call stack.
2418bf67ea1aSBram Moolenaar     while (ectx.ec_frame_idx != initial_frame_idx)
24197eeefd4aSBram Moolenaar 	func_return(&ectx);
24201a2f4bf6SBram Moolenaar failed_early:
2421a26b9700SBram Moolenaar     current_sctx.sc_version = save_sc_version;
2422bf67ea1aSBram Moolenaar 
2423bf67ea1aSBram Moolenaar     // Free all local variables, but not arguments.
24248a7d6542SBram Moolenaar     for (idx = 0; idx < ectx.ec_stack.ga_len; ++idx)
24258a7d6542SBram Moolenaar 	clear_tv(STACK_TV(idx));
2426bf67ea1aSBram Moolenaar 
24278a7d6542SBram Moolenaar     vim_free(ectx.ec_stack.ga_data);
242820431c9dSBram Moolenaar     vim_free(ectx.ec_trystack.ga_data);
24298a7d6542SBram Moolenaar     return ret;
24308a7d6542SBram Moolenaar }
24318a7d6542SBram Moolenaar 
24328a7d6542SBram Moolenaar /*
24338a7d6542SBram Moolenaar  * ":dissassemble".
2434777770fbSBram Moolenaar  * We don't really need this at runtime, but we do have tests that require it,
2435777770fbSBram Moolenaar  * so always include this.
24368a7d6542SBram Moolenaar  */
24378a7d6542SBram Moolenaar     void
24388a7d6542SBram Moolenaar ex_disassemble(exarg_T *eap)
24398a7d6542SBram Moolenaar {
244021456cdcSBram Moolenaar     char_u	*arg = eap->arg;
24410f18b6d1SBram Moolenaar     char_u	*fname;
24420f18b6d1SBram Moolenaar     ufunc_T	*ufunc;
24438a7d6542SBram Moolenaar     dfunc_T	*dfunc;
24448a7d6542SBram Moolenaar     isn_T	*instr;
24458a7d6542SBram Moolenaar     int		current;
24468a7d6542SBram Moolenaar     int		line_idx = 0;
24478a7d6542SBram Moolenaar     int		prev_current = 0;
24484c17ad94SBram Moolenaar     int		is_global = FALSE;
24498a7d6542SBram Moolenaar 
2450bfd65589SBram Moolenaar     if (STRNCMP(arg, "<lambda>", 8) == 0)
2451bfd65589SBram Moolenaar     {
2452bfd65589SBram Moolenaar 	arg += 8;
2453bfd65589SBram Moolenaar 	(void)getdigits(&arg);
2454bfd65589SBram Moolenaar 	fname = vim_strnsave(eap->arg, arg - eap->arg);
2455bfd65589SBram Moolenaar     }
2456bfd65589SBram Moolenaar     else
24574c17ad94SBram Moolenaar 	fname = trans_function_name(&arg, &is_global, FALSE,
2458b68b346eSBram Moolenaar 			    TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD, NULL, NULL);
245921456cdcSBram Moolenaar     if (fname == NULL)
246021456cdcSBram Moolenaar     {
246121456cdcSBram Moolenaar 	semsg(_(e_invarg2), eap->arg);
246221456cdcSBram Moolenaar 	return;
246321456cdcSBram Moolenaar     }
246421456cdcSBram Moolenaar 
24654c17ad94SBram Moolenaar     ufunc = find_func(fname, is_global, NULL);
2466a26b9700SBram Moolenaar     if (ufunc == NULL)
2467a26b9700SBram Moolenaar     {
2468a26b9700SBram Moolenaar 	char_u *p = untrans_function_name(fname);
2469a26b9700SBram Moolenaar 
2470a26b9700SBram Moolenaar 	if (p != NULL)
2471a26b9700SBram Moolenaar 	    // Try again without making it script-local.
24724c17ad94SBram Moolenaar 	    ufunc = find_func(p, FALSE, NULL);
2473a26b9700SBram Moolenaar     }
24740f18b6d1SBram Moolenaar     vim_free(fname);
24758a7d6542SBram Moolenaar     if (ufunc == NULL)
24768a7d6542SBram Moolenaar     {
2477df2ecddfSBram Moolenaar 	semsg(_("E1061: Cannot find function %s"), eap->arg);
24788a7d6542SBram Moolenaar 	return;
24798a7d6542SBram Moolenaar     }
24800cb5bcf5SBram Moolenaar     if (ufunc->uf_def_status == UF_TO_BE_COMPILED
2481822ba247SBram Moolenaar 	    && compile_def_function(ufunc, FALSE, NULL) == FAIL)
2482822ba247SBram Moolenaar 	return;
24830cb5bcf5SBram Moolenaar     if (ufunc->uf_def_status != UF_COMPILED)
24848a7d6542SBram Moolenaar     {
2485df2ecddfSBram Moolenaar 	semsg(_("E1062: Function %s is not compiled"), eap->arg);
24868a7d6542SBram Moolenaar 	return;
24878a7d6542SBram Moolenaar     }
24888a7d6542SBram Moolenaar     if (ufunc->uf_name_exp != NULL)
24898a7d6542SBram Moolenaar 	msg((char *)ufunc->uf_name_exp);
24908a7d6542SBram Moolenaar     else
24918a7d6542SBram Moolenaar 	msg((char *)ufunc->uf_name);
24928a7d6542SBram Moolenaar 
24938a7d6542SBram Moolenaar     dfunc = ((dfunc_T *)def_functions.ga_data) + ufunc->uf_dfunc_idx;
24948a7d6542SBram Moolenaar     instr = dfunc->df_instr;
24958a7d6542SBram Moolenaar     for (current = 0; current < dfunc->df_instr_count; ++current)
24968a7d6542SBram Moolenaar     {
24978a7d6542SBram Moolenaar 	isn_T	    *iptr = &instr[current];
2498f2460a3aSBram Moolenaar 	char	    *line;
24998a7d6542SBram Moolenaar 
25008a7d6542SBram Moolenaar 	while (line_idx < iptr->isn_lnum && line_idx < ufunc->uf_lines.ga_len)
25018a7d6542SBram Moolenaar 	{
25028a7d6542SBram Moolenaar 	    if (current > prev_current)
25038a7d6542SBram Moolenaar 	    {
25048a7d6542SBram Moolenaar 		msg_puts("\n\n");
25058a7d6542SBram Moolenaar 		prev_current = current;
25068a7d6542SBram Moolenaar 	    }
2507f2460a3aSBram Moolenaar 	    line = ((char **)ufunc->uf_lines.ga_data)[line_idx++];
2508f2460a3aSBram Moolenaar 	    if (line != NULL)
2509f2460a3aSBram Moolenaar 		msg(line);
25108a7d6542SBram Moolenaar 	}
25118a7d6542SBram Moolenaar 
25128a7d6542SBram Moolenaar 	switch (iptr->isn_type)
25138a7d6542SBram Moolenaar 	{
25148a7d6542SBram Moolenaar 	    case ISN_EXEC:
25158a7d6542SBram Moolenaar 		smsg("%4d EXEC %s", current, iptr->isn_arg.string);
25168a7d6542SBram Moolenaar 		break;
2517cfe435d7SBram Moolenaar 	    case ISN_EXECCONCAT:
2518cfe435d7SBram Moolenaar 		smsg("%4d EXECCONCAT %lld", current,
2519cfe435d7SBram Moolenaar 					      (long long)iptr->isn_arg.number);
2520cfe435d7SBram Moolenaar 		break;
25218a7d6542SBram Moolenaar 	    case ISN_ECHO:
25228a7d6542SBram Moolenaar 		{
25238a7d6542SBram Moolenaar 		    echo_T *echo = &iptr->isn_arg.echo;
25248a7d6542SBram Moolenaar 
25258a7d6542SBram Moolenaar 		    smsg("%4d %s %d", current,
25268a7d6542SBram Moolenaar 			    echo->echo_with_white ? "ECHO" : "ECHON",
25278a7d6542SBram Moolenaar 			    echo->echo_count);
25288a7d6542SBram Moolenaar 		}
25298a7d6542SBram Moolenaar 		break;
2530ad39c094SBram Moolenaar 	    case ISN_EXECUTE:
25311082772fSBram Moolenaar 		smsg("%4d EXECUTE %lld", current,
25321082772fSBram Moolenaar 					    (long long)(iptr->isn_arg.number));
2533ad39c094SBram Moolenaar 		break;
2534f93c7feaSBram Moolenaar 	    case ISN_ECHOMSG:
2535f93c7feaSBram Moolenaar 		smsg("%4d ECHOMSG %lld", current,
2536f93c7feaSBram Moolenaar 					    (long long)(iptr->isn_arg.number));
2537f93c7feaSBram Moolenaar 		break;
2538f93c7feaSBram Moolenaar 	    case ISN_ECHOERR:
2539f93c7feaSBram Moolenaar 		smsg("%4d ECHOERR %lld", current,
2540f93c7feaSBram Moolenaar 					    (long long)(iptr->isn_arg.number));
2541f93c7feaSBram Moolenaar 		break;
25428a7d6542SBram Moolenaar 	    case ISN_LOAD:
2543c8cd2b34SBram Moolenaar 	    case ISN_LOADOUTER:
2544c8cd2b34SBram Moolenaar 		{
2545c8cd2b34SBram Moolenaar 		    char *add = iptr->isn_type == ISN_LOAD ? "" : "OUTER";
2546c8cd2b34SBram Moolenaar 
25478a7d6542SBram Moolenaar 		    if (iptr->isn_arg.number < 0)
2548c8cd2b34SBram Moolenaar 			smsg("%4d LOAD%s arg[%lld]", current, add,
2549c8cd2b34SBram Moolenaar 				(long long)(iptr->isn_arg.number
2550c8cd2b34SBram Moolenaar 							  + STACK_FRAME_SIZE));
25518a7d6542SBram Moolenaar 		    else
2552c8cd2b34SBram Moolenaar 			smsg("%4d LOAD%s $%lld", current, add,
25531082772fSBram Moolenaar 					    (long long)(iptr->isn_arg.number));
2554c8cd2b34SBram Moolenaar 		}
25558a7d6542SBram Moolenaar 		break;
25568a7d6542SBram Moolenaar 	    case ISN_LOADV:
25578a7d6542SBram Moolenaar 		smsg("%4d LOADV v:%s", current,
25588a7d6542SBram Moolenaar 				       get_vim_var_name(iptr->isn_arg.number));
25598a7d6542SBram Moolenaar 		break;
25608a7d6542SBram Moolenaar 	    case ISN_LOADSCRIPT:
25618a7d6542SBram Moolenaar 		{
25628a7d6542SBram Moolenaar 		    scriptitem_T *si =
256321b9e977SBram Moolenaar 				  SCRIPT_ITEM(iptr->isn_arg.script.script_sid);
25648a7d6542SBram Moolenaar 		    svar_T *sv = ((svar_T *)si->sn_var_vals.ga_data)
25658a7d6542SBram Moolenaar 					     + iptr->isn_arg.script.script_idx;
25668a7d6542SBram Moolenaar 
25678a7d6542SBram Moolenaar 		    smsg("%4d LOADSCRIPT %s from %s", current,
25688a7d6542SBram Moolenaar 						     sv->sv_name, si->sn_name);
25698a7d6542SBram Moolenaar 		}
25708a7d6542SBram Moolenaar 		break;
25718a7d6542SBram Moolenaar 	    case ISN_LOADS:
25728a7d6542SBram Moolenaar 		{
2573b283a8a6SBram Moolenaar 		    scriptitem_T *si = SCRIPT_ITEM(
2574b283a8a6SBram Moolenaar 					       iptr->isn_arg.loadstore.ls_sid);
25758a7d6542SBram Moolenaar 
25768a7d6542SBram Moolenaar 		    smsg("%4d LOADS s:%s from %s", current,
25775deeb3f1SBram Moolenaar 				 iptr->isn_arg.loadstore.ls_name, si->sn_name);
25788a7d6542SBram Moolenaar 		}
25798a7d6542SBram Moolenaar 		break;
25808a7d6542SBram Moolenaar 	    case ISN_LOADG:
25818a7d6542SBram Moolenaar 		smsg("%4d LOADG g:%s", current, iptr->isn_arg.string);
25828a7d6542SBram Moolenaar 		break;
2583d3aac291SBram Moolenaar 	    case ISN_LOADB:
2584d3aac291SBram Moolenaar 		smsg("%4d LOADB b:%s", current, iptr->isn_arg.string);
2585d3aac291SBram Moolenaar 		break;
2586d3aac291SBram Moolenaar 	    case ISN_LOADW:
2587d3aac291SBram Moolenaar 		smsg("%4d LOADW w:%s", current, iptr->isn_arg.string);
2588d3aac291SBram Moolenaar 		break;
2589d3aac291SBram Moolenaar 	    case ISN_LOADT:
2590d3aac291SBram Moolenaar 		smsg("%4d LOADT t:%s", current, iptr->isn_arg.string);
2591d3aac291SBram Moolenaar 		break;
25928a7d6542SBram Moolenaar 	    case ISN_LOADOPT:
25938a7d6542SBram Moolenaar 		smsg("%4d LOADOPT %s", current, iptr->isn_arg.string);
25948a7d6542SBram Moolenaar 		break;
25958a7d6542SBram Moolenaar 	    case ISN_LOADENV:
25968a7d6542SBram Moolenaar 		smsg("%4d LOADENV %s", current, iptr->isn_arg.string);
25978a7d6542SBram Moolenaar 		break;
25988a7d6542SBram Moolenaar 	    case ISN_LOADREG:
25991082772fSBram Moolenaar 		smsg("%4d LOADREG @%c", current, (int)(iptr->isn_arg.number));
26008a7d6542SBram Moolenaar 		break;
26018a7d6542SBram Moolenaar 
26028a7d6542SBram Moolenaar 	    case ISN_STORE:
2603b68b346eSBram Moolenaar 	    case ISN_STOREOUTER:
2604b68b346eSBram Moolenaar 		{
2605b68b346eSBram Moolenaar 		    char *add = iptr->isn_type == ISN_STORE ? "" : "OUTER";
2606b68b346eSBram Moolenaar 
2607170fcfcfSBram Moolenaar 		if (iptr->isn_arg.number < 0)
2608b68b346eSBram Moolenaar 		    smsg("%4d STORE%s arg[%lld]", current, add,
2609db99f9f2SBram Moolenaar 			 (long long)(iptr->isn_arg.number + STACK_FRAME_SIZE));
2610170fcfcfSBram Moolenaar 		else
2611b68b346eSBram Moolenaar 		    smsg("%4d STORE%s $%lld", current, add,
26121082772fSBram Moolenaar 					    (long long)(iptr->isn_arg.number));
2613b68b346eSBram Moolenaar 		}
26148a7d6542SBram Moolenaar 		break;
2615b283a8a6SBram Moolenaar 	    case ISN_STOREV:
2616b283a8a6SBram Moolenaar 		smsg("%4d STOREV v:%s", current,
2617b283a8a6SBram Moolenaar 				       get_vim_var_name(iptr->isn_arg.number));
2618b283a8a6SBram Moolenaar 		break;
26198a7d6542SBram Moolenaar 	    case ISN_STOREG:
2620b283a8a6SBram Moolenaar 		smsg("%4d STOREG %s", current, iptr->isn_arg.string);
2621b283a8a6SBram Moolenaar 		break;
2622d3aac291SBram Moolenaar 	    case ISN_STOREB:
2623d3aac291SBram Moolenaar 		smsg("%4d STOREB %s", current, iptr->isn_arg.string);
2624d3aac291SBram Moolenaar 		break;
2625d3aac291SBram Moolenaar 	    case ISN_STOREW:
2626d3aac291SBram Moolenaar 		smsg("%4d STOREW %s", current, iptr->isn_arg.string);
2627d3aac291SBram Moolenaar 		break;
2628d3aac291SBram Moolenaar 	    case ISN_STORET:
2629d3aac291SBram Moolenaar 		smsg("%4d STORET %s", current, iptr->isn_arg.string);
2630d3aac291SBram Moolenaar 		break;
2631b283a8a6SBram Moolenaar 	    case ISN_STORES:
2632b283a8a6SBram Moolenaar 		{
2633b283a8a6SBram Moolenaar 		    scriptitem_T *si = SCRIPT_ITEM(
2634b283a8a6SBram Moolenaar 					       iptr->isn_arg.loadstore.ls_sid);
2635b283a8a6SBram Moolenaar 
26360bbf722aSBram Moolenaar 		    smsg("%4d STORES %s in %s", current,
26375deeb3f1SBram Moolenaar 				 iptr->isn_arg.loadstore.ls_name, si->sn_name);
2638b283a8a6SBram Moolenaar 		}
26398a7d6542SBram Moolenaar 		break;
26408a7d6542SBram Moolenaar 	    case ISN_STORESCRIPT:
26418a7d6542SBram Moolenaar 		{
26428a7d6542SBram Moolenaar 		    scriptitem_T *si =
264321b9e977SBram Moolenaar 				  SCRIPT_ITEM(iptr->isn_arg.script.script_sid);
26448a7d6542SBram Moolenaar 		    svar_T *sv = ((svar_T *)si->sn_var_vals.ga_data)
26458a7d6542SBram Moolenaar 					     + iptr->isn_arg.script.script_idx;
26468a7d6542SBram Moolenaar 
26478a7d6542SBram Moolenaar 		    smsg("%4d STORESCRIPT %s in %s", current,
26488a7d6542SBram Moolenaar 						     sv->sv_name, si->sn_name);
26498a7d6542SBram Moolenaar 		}
26508a7d6542SBram Moolenaar 		break;
26518a7d6542SBram Moolenaar 	    case ISN_STOREOPT:
26528a7d6542SBram Moolenaar 		smsg("%4d STOREOPT &%s", current,
26538a7d6542SBram Moolenaar 					       iptr->isn_arg.storeopt.so_name);
26548a7d6542SBram Moolenaar 		break;
2655b283a8a6SBram Moolenaar 	    case ISN_STOREENV:
2656b283a8a6SBram Moolenaar 		smsg("%4d STOREENV $%s", current, iptr->isn_arg.string);
2657b283a8a6SBram Moolenaar 		break;
2658b283a8a6SBram Moolenaar 	    case ISN_STOREREG:
26591082772fSBram Moolenaar 		smsg("%4d STOREREG @%c", current, (int)iptr->isn_arg.number);
2660b283a8a6SBram Moolenaar 		break;
26618a7d6542SBram Moolenaar 	    case ISN_STORENR:
26628a7d6542SBram Moolenaar 		smsg("%4d STORE %lld in $%d", current,
2663a471eeaeSBram Moolenaar 				iptr->isn_arg.storenr.stnr_val,
2664a471eeaeSBram Moolenaar 				iptr->isn_arg.storenr.stnr_idx);
26658a7d6542SBram Moolenaar 		break;
26668a7d6542SBram Moolenaar 
26671cc2a94fSBram Moolenaar 	    case ISN_STORELIST:
26681cc2a94fSBram Moolenaar 		smsg("%4d STORELIST", current);
26691cc2a94fSBram Moolenaar 		break;
26701cc2a94fSBram Moolenaar 
26711cc2a94fSBram Moolenaar 	    case ISN_STOREDICT:
26721cc2a94fSBram Moolenaar 		smsg("%4d STOREDICT", current);
26731cc2a94fSBram Moolenaar 		break;
26741cc2a94fSBram Moolenaar 
26758a7d6542SBram Moolenaar 	    // constants
26768a7d6542SBram Moolenaar 	    case ISN_PUSHNR:
26771082772fSBram Moolenaar 		smsg("%4d PUSHNR %lld", current,
26781082772fSBram Moolenaar 					    (long long)(iptr->isn_arg.number));
26798a7d6542SBram Moolenaar 		break;
26808a7d6542SBram Moolenaar 	    case ISN_PUSHBOOL:
26818a7d6542SBram Moolenaar 	    case ISN_PUSHSPEC:
26828a7d6542SBram Moolenaar 		smsg("%4d PUSH %s", current,
26838a7d6542SBram Moolenaar 				   get_var_special_name(iptr->isn_arg.number));
26848a7d6542SBram Moolenaar 		break;
26858a7d6542SBram Moolenaar 	    case ISN_PUSHF:
2686a5d5953dSBram Moolenaar #ifdef FEAT_FLOAT
26878a7d6542SBram Moolenaar 		smsg("%4d PUSHF %g", current, iptr->isn_arg.fnumber);
2688a5d5953dSBram Moolenaar #endif
26898a7d6542SBram Moolenaar 		break;
26908a7d6542SBram Moolenaar 	    case ISN_PUSHS:
26918a7d6542SBram Moolenaar 		smsg("%4d PUSHS \"%s\"", current, iptr->isn_arg.string);
26928a7d6542SBram Moolenaar 		break;
26938a7d6542SBram Moolenaar 	    case ISN_PUSHBLOB:
26948a7d6542SBram Moolenaar 		{
26958a7d6542SBram Moolenaar 		    char_u	*r;
26968a7d6542SBram Moolenaar 		    char_u	numbuf[NUMBUFLEN];
26978a7d6542SBram Moolenaar 		    char_u	*tofree;
26988a7d6542SBram Moolenaar 
26998a7d6542SBram Moolenaar 		    r = blob2string(iptr->isn_arg.blob, &tofree, numbuf);
2700ff80cb68SBram Moolenaar 		    smsg("%4d PUSHBLOB %s", current, r);
27018a7d6542SBram Moolenaar 		    vim_free(tofree);
27028a7d6542SBram Moolenaar 		}
27038a7d6542SBram Moolenaar 		break;
270442a480bfSBram Moolenaar 	    case ISN_PUSHFUNC:
2705087d2e15SBram Moolenaar 		{
2706087d2e15SBram Moolenaar 		    char *name = (char *)iptr->isn_arg.string;
2707087d2e15SBram Moolenaar 
2708087d2e15SBram Moolenaar 		    smsg("%4d PUSHFUNC \"%s\"", current,
2709087d2e15SBram Moolenaar 					       name == NULL ? "[none]" : name);
2710087d2e15SBram Moolenaar 		}
271142a480bfSBram Moolenaar 		break;
271242a480bfSBram Moolenaar 	    case ISN_PUSHCHANNEL:
271342a480bfSBram Moolenaar #ifdef FEAT_JOB_CHANNEL
271442a480bfSBram Moolenaar 		{
271542a480bfSBram Moolenaar 		    channel_T *channel = iptr->isn_arg.channel;
271642a480bfSBram Moolenaar 
271742a480bfSBram Moolenaar 		    smsg("%4d PUSHCHANNEL %d", current,
271842a480bfSBram Moolenaar 					 channel == NULL ? 0 : channel->ch_id);
271942a480bfSBram Moolenaar 		}
272042a480bfSBram Moolenaar #endif
272142a480bfSBram Moolenaar 		break;
272242a480bfSBram Moolenaar 	    case ISN_PUSHJOB:
272342a480bfSBram Moolenaar #ifdef FEAT_JOB_CHANNEL
272442a480bfSBram Moolenaar 		{
272542a480bfSBram Moolenaar 		    typval_T	tv;
272642a480bfSBram Moolenaar 		    char_u	*name;
272742a480bfSBram Moolenaar 
272842a480bfSBram Moolenaar 		    tv.v_type = VAR_JOB;
272942a480bfSBram Moolenaar 		    tv.vval.v_job = iptr->isn_arg.job;
273042a480bfSBram Moolenaar 		    name = tv_get_string(&tv);
2731f51cb4e0SBram Moolenaar 		    smsg("%4d PUSHJOB \"%s\"", current, name);
273242a480bfSBram Moolenaar 		}
273342a480bfSBram Moolenaar #endif
273442a480bfSBram Moolenaar 		break;
27358a7d6542SBram Moolenaar 	    case ISN_PUSHEXC:
27368a7d6542SBram Moolenaar 		smsg("%4d PUSH v:exception", current);
27378a7d6542SBram Moolenaar 		break;
2738d72c1bf0SBram Moolenaar 	    case ISN_UNLET:
2739d72c1bf0SBram Moolenaar 		smsg("%4d UNLET%s %s", current,
2740d72c1bf0SBram Moolenaar 			iptr->isn_arg.unlet.ul_forceit ? "!" : "",
2741d72c1bf0SBram Moolenaar 			iptr->isn_arg.unlet.ul_name);
2742d72c1bf0SBram Moolenaar 		break;
27437bdaea6eSBram Moolenaar 	    case ISN_UNLETENV:
27447bdaea6eSBram Moolenaar 		smsg("%4d UNLETENV%s $%s", current,
27457bdaea6eSBram Moolenaar 			iptr->isn_arg.unlet.ul_forceit ? "!" : "",
27467bdaea6eSBram Moolenaar 			iptr->isn_arg.unlet.ul_name);
27477bdaea6eSBram Moolenaar 		break;
27488a7d6542SBram Moolenaar 	    case ISN_NEWLIST:
27491082772fSBram Moolenaar 		smsg("%4d NEWLIST size %lld", current,
27501082772fSBram Moolenaar 					    (long long)(iptr->isn_arg.number));
27518a7d6542SBram Moolenaar 		break;
27528a7d6542SBram Moolenaar 	    case ISN_NEWDICT:
27531082772fSBram Moolenaar 		smsg("%4d NEWDICT size %lld", current,
27541082772fSBram Moolenaar 					    (long long)(iptr->isn_arg.number));
27558a7d6542SBram Moolenaar 		break;
27568a7d6542SBram Moolenaar 
27578a7d6542SBram Moolenaar 	    // function call
27588a7d6542SBram Moolenaar 	    case ISN_BCALL:
27598a7d6542SBram Moolenaar 		{
27608a7d6542SBram Moolenaar 		    cbfunc_T	*cbfunc = &iptr->isn_arg.bfunc;
27618a7d6542SBram Moolenaar 
27628a7d6542SBram Moolenaar 		    smsg("%4d BCALL %s(argc %d)", current,
27638a7d6542SBram Moolenaar 			    internal_func_name(cbfunc->cbf_idx),
27648a7d6542SBram Moolenaar 			    cbfunc->cbf_argcount);
27658a7d6542SBram Moolenaar 		}
27668a7d6542SBram Moolenaar 		break;
27678a7d6542SBram Moolenaar 	    case ISN_DCALL:
27688a7d6542SBram Moolenaar 		{
27698a7d6542SBram Moolenaar 		    cdfunc_T	*cdfunc = &iptr->isn_arg.dfunc;
27708a7d6542SBram Moolenaar 		    dfunc_T	*df = ((dfunc_T *)def_functions.ga_data)
27718a7d6542SBram Moolenaar 							     + cdfunc->cdf_idx;
27728a7d6542SBram Moolenaar 
27738a7d6542SBram Moolenaar 		    smsg("%4d DCALL %s(argc %d)", current,
27748a7d6542SBram Moolenaar 			    df->df_ufunc->uf_name_exp != NULL
27758a7d6542SBram Moolenaar 				? df->df_ufunc->uf_name_exp
27768a7d6542SBram Moolenaar 				: df->df_ufunc->uf_name, cdfunc->cdf_argcount);
27778a7d6542SBram Moolenaar 		}
27788a7d6542SBram Moolenaar 		break;
27798a7d6542SBram Moolenaar 	    case ISN_UCALL:
27808a7d6542SBram Moolenaar 		{
27818a7d6542SBram Moolenaar 		    cufunc_T	*cufunc = &iptr->isn_arg.ufunc;
27828a7d6542SBram Moolenaar 
27838a7d6542SBram Moolenaar 		    smsg("%4d UCALL %s(argc %d)", current,
27848a7d6542SBram Moolenaar 				       cufunc->cuf_name, cufunc->cuf_argcount);
27858a7d6542SBram Moolenaar 		}
27868a7d6542SBram Moolenaar 		break;
27878a7d6542SBram Moolenaar 	    case ISN_PCALL:
27888a7d6542SBram Moolenaar 		{
27898a7d6542SBram Moolenaar 		    cpfunc_T	*cpfunc = &iptr->isn_arg.pfunc;
27908a7d6542SBram Moolenaar 
27918a7d6542SBram Moolenaar 		    smsg("%4d PCALL%s (argc %d)", current,
27928a7d6542SBram Moolenaar 			   cpfunc->cpf_top ? " top" : "", cpfunc->cpf_argcount);
27938a7d6542SBram Moolenaar 		}
27948a7d6542SBram Moolenaar 		break;
2795bd5da371SBram Moolenaar 	    case ISN_PCALL_END:
2796bd5da371SBram Moolenaar 		smsg("%4d PCALL end", current);
2797bd5da371SBram Moolenaar 		break;
27988a7d6542SBram Moolenaar 	    case ISN_RETURN:
27998a7d6542SBram Moolenaar 		smsg("%4d RETURN", current);
28008a7d6542SBram Moolenaar 		break;
28018a7d6542SBram Moolenaar 	    case ISN_FUNCREF:
28028a7d6542SBram Moolenaar 		{
28035adc55cbSBram Moolenaar 		    funcref_T	*funcref = &iptr->isn_arg.funcref;
28048a7d6542SBram Moolenaar 		    dfunc_T	*df = ((dfunc_T *)def_functions.ga_data)
28055adc55cbSBram Moolenaar 							    + funcref->fr_func;
28068a7d6542SBram Moolenaar 
2807bf67ea1aSBram Moolenaar 		    smsg("%4d FUNCREF %s $%d", current, df->df_ufunc->uf_name,
28085adc55cbSBram Moolenaar 				     funcref->fr_var_idx + dfunc->df_varcount);
28098a7d6542SBram Moolenaar 		}
28108a7d6542SBram Moolenaar 		break;
28118a7d6542SBram Moolenaar 
28128a7d6542SBram Moolenaar 	    case ISN_JUMP:
28138a7d6542SBram Moolenaar 		{
28148a7d6542SBram Moolenaar 		    char *when = "?";
28158a7d6542SBram Moolenaar 
28168a7d6542SBram Moolenaar 		    switch (iptr->isn_arg.jump.jump_when)
28178a7d6542SBram Moolenaar 		    {
28188a7d6542SBram Moolenaar 			case JUMP_ALWAYS:
28198a7d6542SBram Moolenaar 			    when = "JUMP";
28208a7d6542SBram Moolenaar 			    break;
28218a7d6542SBram Moolenaar 			case JUMP_AND_KEEP_IF_TRUE:
28228a7d6542SBram Moolenaar 			    when = "JUMP_AND_KEEP_IF_TRUE";
28238a7d6542SBram Moolenaar 			    break;
28248a7d6542SBram Moolenaar 			case JUMP_IF_FALSE:
28258a7d6542SBram Moolenaar 			    when = "JUMP_IF_FALSE";
28268a7d6542SBram Moolenaar 			    break;
28278a7d6542SBram Moolenaar 			case JUMP_AND_KEEP_IF_FALSE:
28288a7d6542SBram Moolenaar 			    when = "JUMP_AND_KEEP_IF_FALSE";
28298a7d6542SBram Moolenaar 			    break;
28308a7d6542SBram Moolenaar 		    }
28318a677a37SBram Moolenaar 		    smsg("%4d %s -> %d", current, when,
28328a7d6542SBram Moolenaar 						iptr->isn_arg.jump.jump_where);
28338a7d6542SBram Moolenaar 		}
28348a7d6542SBram Moolenaar 		break;
28358a7d6542SBram Moolenaar 
28368a7d6542SBram Moolenaar 	    case ISN_FOR:
28378a7d6542SBram Moolenaar 		{
28388a7d6542SBram Moolenaar 		    forloop_T *forloop = &iptr->isn_arg.forloop;
28398a7d6542SBram Moolenaar 
28408a7d6542SBram Moolenaar 		    smsg("%4d FOR $%d -> %d", current,
28418a7d6542SBram Moolenaar 					   forloop->for_idx, forloop->for_end);
28428a7d6542SBram Moolenaar 		}
28438a7d6542SBram Moolenaar 		break;
28448a7d6542SBram Moolenaar 
28458a7d6542SBram Moolenaar 	    case ISN_TRY:
28468a7d6542SBram Moolenaar 		{
28478a7d6542SBram Moolenaar 		    try_T *try = &iptr->isn_arg.try;
28488a7d6542SBram Moolenaar 
28498a7d6542SBram Moolenaar 		    smsg("%4d TRY catch -> %d, finally -> %d", current,
28508a7d6542SBram Moolenaar 					     try->try_catch, try->try_finally);
28518a7d6542SBram Moolenaar 		}
28528a7d6542SBram Moolenaar 		break;
28538a7d6542SBram Moolenaar 	    case ISN_CATCH:
28548a7d6542SBram Moolenaar 		// TODO
28558a7d6542SBram Moolenaar 		smsg("%4d CATCH", current);
28568a7d6542SBram Moolenaar 		break;
28578a7d6542SBram Moolenaar 	    case ISN_ENDTRY:
28588a7d6542SBram Moolenaar 		smsg("%4d ENDTRY", current);
28598a7d6542SBram Moolenaar 		break;
28608a7d6542SBram Moolenaar 	    case ISN_THROW:
28618a7d6542SBram Moolenaar 		smsg("%4d THROW", current);
28628a7d6542SBram Moolenaar 		break;
28638a7d6542SBram Moolenaar 
28648a7d6542SBram Moolenaar 	    // expression operations on number
28658a7d6542SBram Moolenaar 	    case ISN_OPNR:
28668a7d6542SBram Moolenaar 	    case ISN_OPFLOAT:
28678a7d6542SBram Moolenaar 	    case ISN_OPANY:
28688a7d6542SBram Moolenaar 		{
28698a7d6542SBram Moolenaar 		    char *what;
28708a7d6542SBram Moolenaar 		    char *ins;
28718a7d6542SBram Moolenaar 
28728a7d6542SBram Moolenaar 		    switch (iptr->isn_arg.op.op_type)
28738a7d6542SBram Moolenaar 		    {
28748a7d6542SBram Moolenaar 			case EXPR_MULT: what = "*"; break;
28758a7d6542SBram Moolenaar 			case EXPR_DIV: what = "/"; break;
28768a7d6542SBram Moolenaar 			case EXPR_REM: what = "%"; break;
28778a7d6542SBram Moolenaar 			case EXPR_SUB: what = "-"; break;
28788a7d6542SBram Moolenaar 			case EXPR_ADD: what = "+"; break;
28798a7d6542SBram Moolenaar 			default:       what = "???"; break;
28808a7d6542SBram Moolenaar 		    }
28818a7d6542SBram Moolenaar 		    switch (iptr->isn_type)
28828a7d6542SBram Moolenaar 		    {
28838a7d6542SBram Moolenaar 			case ISN_OPNR: ins = "OPNR"; break;
28848a7d6542SBram Moolenaar 			case ISN_OPFLOAT: ins = "OPFLOAT"; break;
28858a7d6542SBram Moolenaar 			case ISN_OPANY: ins = "OPANY"; break;
28868a7d6542SBram Moolenaar 			default: ins = "???"; break;
28878a7d6542SBram Moolenaar 		    }
28888a7d6542SBram Moolenaar 		    smsg("%4d %s %s", current, ins, what);
28898a7d6542SBram Moolenaar 		}
28908a7d6542SBram Moolenaar 		break;
28918a7d6542SBram Moolenaar 
28928a7d6542SBram Moolenaar 	    case ISN_COMPAREBOOL:
28938a7d6542SBram Moolenaar 	    case ISN_COMPARESPECIAL:
28948a7d6542SBram Moolenaar 	    case ISN_COMPARENR:
28958a7d6542SBram Moolenaar 	    case ISN_COMPAREFLOAT:
28968a7d6542SBram Moolenaar 	    case ISN_COMPARESTRING:
28978a7d6542SBram Moolenaar 	    case ISN_COMPAREBLOB:
28988a7d6542SBram Moolenaar 	    case ISN_COMPARELIST:
28998a7d6542SBram Moolenaar 	    case ISN_COMPAREDICT:
29008a7d6542SBram Moolenaar 	    case ISN_COMPAREFUNC:
29018a7d6542SBram Moolenaar 	    case ISN_COMPAREANY:
29028a7d6542SBram Moolenaar 		   {
29038a7d6542SBram Moolenaar 		       char *p;
29048a7d6542SBram Moolenaar 		       char buf[10];
29058a7d6542SBram Moolenaar 		       char *type;
29068a7d6542SBram Moolenaar 
29078a7d6542SBram Moolenaar 		       switch (iptr->isn_arg.op.op_type)
29088a7d6542SBram Moolenaar 		       {
29098a7d6542SBram Moolenaar 			   case EXPR_EQUAL:	 p = "=="; break;
29108a7d6542SBram Moolenaar 			   case EXPR_NEQUAL:    p = "!="; break;
29118a7d6542SBram Moolenaar 			   case EXPR_GREATER:   p = ">"; break;
29128a7d6542SBram Moolenaar 			   case EXPR_GEQUAL:    p = ">="; break;
29138a7d6542SBram Moolenaar 			   case EXPR_SMALLER:   p = "<"; break;
29148a7d6542SBram Moolenaar 			   case EXPR_SEQUAL:    p = "<="; break;
29158a7d6542SBram Moolenaar 			   case EXPR_MATCH:	 p = "=~"; break;
29168a7d6542SBram Moolenaar 			   case EXPR_IS:	 p = "is"; break;
29178a7d6542SBram Moolenaar 			   case EXPR_ISNOT:	 p = "isnot"; break;
29188a7d6542SBram Moolenaar 			   case EXPR_NOMATCH:	 p = "!~"; break;
29198a7d6542SBram Moolenaar 			   default:  p = "???"; break;
29208a7d6542SBram Moolenaar 		       }
29218a7d6542SBram Moolenaar 		       STRCPY(buf, p);
29228a7d6542SBram Moolenaar 		       if (iptr->isn_arg.op.op_ic == TRUE)
29238a7d6542SBram Moolenaar 			   strcat(buf, "?");
29248a7d6542SBram Moolenaar 		       switch(iptr->isn_type)
29258a7d6542SBram Moolenaar 		       {
29268a7d6542SBram Moolenaar 			   case ISN_COMPAREBOOL: type = "COMPAREBOOL"; break;
29278a7d6542SBram Moolenaar 			   case ISN_COMPARESPECIAL:
29288a7d6542SBram Moolenaar 						 type = "COMPARESPECIAL"; break;
29298a7d6542SBram Moolenaar 			   case ISN_COMPARENR: type = "COMPARENR"; break;
29308a7d6542SBram Moolenaar 			   case ISN_COMPAREFLOAT: type = "COMPAREFLOAT"; break;
29318a7d6542SBram Moolenaar 			   case ISN_COMPARESTRING:
29328a7d6542SBram Moolenaar 						  type = "COMPARESTRING"; break;
29338a7d6542SBram Moolenaar 			   case ISN_COMPAREBLOB: type = "COMPAREBLOB"; break;
29348a7d6542SBram Moolenaar 			   case ISN_COMPARELIST: type = "COMPARELIST"; break;
29358a7d6542SBram Moolenaar 			   case ISN_COMPAREDICT: type = "COMPAREDICT"; break;
29368a7d6542SBram Moolenaar 			   case ISN_COMPAREFUNC: type = "COMPAREFUNC"; break;
29378a7d6542SBram Moolenaar 			   case ISN_COMPAREANY: type = "COMPAREANY"; break;
29388a7d6542SBram Moolenaar 			   default: type = "???"; break;
29398a7d6542SBram Moolenaar 		       }
29408a7d6542SBram Moolenaar 
29418a7d6542SBram Moolenaar 		       smsg("%4d %s %s", current, type, buf);
29428a7d6542SBram Moolenaar 		   }
29438a7d6542SBram Moolenaar 		   break;
29448a7d6542SBram Moolenaar 
29458a7d6542SBram Moolenaar 	    case ISN_ADDLIST: smsg("%4d ADDLIST", current); break;
29468a7d6542SBram Moolenaar 	    case ISN_ADDBLOB: smsg("%4d ADDBLOB", current); break;
29478a7d6542SBram Moolenaar 
29488a7d6542SBram Moolenaar 	    // expression operations
29498a7d6542SBram Moolenaar 	    case ISN_CONCAT: smsg("%4d CONCAT", current); break;
29508a7d6542SBram Moolenaar 	    case ISN_INDEX: smsg("%4d INDEX", current); break;
29519af78769SBram Moolenaar 	    case ISN_SLICE: smsg("%4d SLICE %lld",
29529af78769SBram Moolenaar 					 current, iptr->isn_arg.number); break;
295347a519a9SBram Moolenaar 	    case ISN_GETITEM: smsg("%4d ITEM %lld",
295447a519a9SBram Moolenaar 					 current, iptr->isn_arg.number); break;
29551cc2a94fSBram Moolenaar 	    case ISN_MEMBER: smsg("%4d MEMBER", current); break;
29561cc2a94fSBram Moolenaar 	    case ISN_STRINGMEMBER: smsg("%4d MEMBER %s", current,
29578a7d6542SBram Moolenaar 						  iptr->isn_arg.string); break;
29588a7d6542SBram Moolenaar 	    case ISN_NEGATENR: smsg("%4d NEGATENR", current); break;
29598a7d6542SBram Moolenaar 
29608a7d6542SBram Moolenaar 	    case ISN_CHECKNR: smsg("%4d CHECKNR", current); break;
29618a7d6542SBram Moolenaar 	    case ISN_CHECKTYPE: smsg("%4d CHECKTYPE %s stack[%d]", current,
29628a7d6542SBram Moolenaar 				      vartype_name(iptr->isn_arg.type.ct_type),
29638a7d6542SBram Moolenaar 				      iptr->isn_arg.type.ct_off);
29648a7d6542SBram Moolenaar 				break;
29659af78769SBram Moolenaar 	    case ISN_CHECKLEN: smsg("%4d CHECKLEN %s%d", current,
29669af78769SBram Moolenaar 				iptr->isn_arg.checklen.cl_more_OK ? ">= " : "",
29679af78769SBram Moolenaar 				iptr->isn_arg.checklen.cl_min_len);
29689af78769SBram Moolenaar 			       break;
29698a7d6542SBram Moolenaar 	    case ISN_2BOOL: if (iptr->isn_arg.number)
29708a7d6542SBram Moolenaar 				smsg("%4d INVERT (!val)", current);
29718a7d6542SBram Moolenaar 			    else
29728a7d6542SBram Moolenaar 				smsg("%4d 2BOOL (!!val)", current);
29738a7d6542SBram Moolenaar 			    break;
2974db99f9f2SBram Moolenaar 	    case ISN_2STRING: smsg("%4d 2STRING stack[%lld]", current,
2975db99f9f2SBram Moolenaar 					 (long long)(iptr->isn_arg.number));
29768a7d6542SBram Moolenaar 			      break;
29778a7d6542SBram Moolenaar 
2978389df259SBram Moolenaar 	    case ISN_SHUFFLE: smsg("%4d SHUFFLE %d up %d", current,
2979389df259SBram Moolenaar 					 iptr->isn_arg.shuffle.shfl_item,
2980389df259SBram Moolenaar 					 iptr->isn_arg.shuffle.shfl_up);
2981389df259SBram Moolenaar 			      break;
29828a7d6542SBram Moolenaar 	    case ISN_DROP: smsg("%4d DROP", current); break;
29838a7d6542SBram Moolenaar 	}
29848a7d6542SBram Moolenaar     }
29858a7d6542SBram Moolenaar }
29868a7d6542SBram Moolenaar 
29878a7d6542SBram Moolenaar /*
29888a7d6542SBram Moolenaar  * Return TRUE when "tv" is not falsey: non-zero, non-empty string, non-empty
29898a7d6542SBram Moolenaar  * list, etc.  Mostly like what JavaScript does, except that empty list and
29908a7d6542SBram Moolenaar  * empty dictionary are FALSE.
29918a7d6542SBram Moolenaar  */
29928a7d6542SBram Moolenaar     int
29938a7d6542SBram Moolenaar tv2bool(typval_T *tv)
29948a7d6542SBram Moolenaar {
29958a7d6542SBram Moolenaar     switch (tv->v_type)
29968a7d6542SBram Moolenaar     {
29978a7d6542SBram Moolenaar 	case VAR_NUMBER:
29988a7d6542SBram Moolenaar 	    return tv->vval.v_number != 0;
29998a7d6542SBram Moolenaar 	case VAR_FLOAT:
30008a7d6542SBram Moolenaar #ifdef FEAT_FLOAT
30018a7d6542SBram Moolenaar 	    return tv->vval.v_float != 0.0;
30028a7d6542SBram Moolenaar #else
30038a7d6542SBram Moolenaar 	    break;
30048a7d6542SBram Moolenaar #endif
30058a7d6542SBram Moolenaar 	case VAR_PARTIAL:
30068a7d6542SBram Moolenaar 	    return tv->vval.v_partial != NULL;
30078a7d6542SBram Moolenaar 	case VAR_FUNC:
30088a7d6542SBram Moolenaar 	case VAR_STRING:
30098a7d6542SBram Moolenaar 	    return tv->vval.v_string != NULL && *tv->vval.v_string != NUL;
30108a7d6542SBram Moolenaar 	case VAR_LIST:
30118a7d6542SBram Moolenaar 	    return tv->vval.v_list != NULL && tv->vval.v_list->lv_len > 0;
30128a7d6542SBram Moolenaar 	case VAR_DICT:
30138a7d6542SBram Moolenaar 	    return tv->vval.v_dict != NULL
30148a7d6542SBram Moolenaar 				    && tv->vval.v_dict->dv_hashtab.ht_used > 0;
30158a7d6542SBram Moolenaar 	case VAR_BOOL:
30168a7d6542SBram Moolenaar 	case VAR_SPECIAL:
30178a7d6542SBram Moolenaar 	    return tv->vval.v_number == VVAL_TRUE ? TRUE : FALSE;
30188a7d6542SBram Moolenaar 	case VAR_JOB:
30198a7d6542SBram Moolenaar #ifdef FEAT_JOB_CHANNEL
30208a7d6542SBram Moolenaar 	    return tv->vval.v_job != NULL;
30218a7d6542SBram Moolenaar #else
30228a7d6542SBram Moolenaar 	    break;
30238a7d6542SBram Moolenaar #endif
30248a7d6542SBram Moolenaar 	case VAR_CHANNEL:
30258a7d6542SBram Moolenaar #ifdef FEAT_JOB_CHANNEL
30268a7d6542SBram Moolenaar 	    return tv->vval.v_channel != NULL;
30278a7d6542SBram Moolenaar #else
30288a7d6542SBram Moolenaar 	    break;
30298a7d6542SBram Moolenaar #endif
30308a7d6542SBram Moolenaar 	case VAR_BLOB:
30318a7d6542SBram Moolenaar 	    return tv->vval.v_blob != NULL && tv->vval.v_blob->bv_ga.ga_len > 0;
30328a7d6542SBram Moolenaar 	case VAR_UNKNOWN:
30334c683750SBram Moolenaar 	case VAR_ANY:
30348a7d6542SBram Moolenaar 	case VAR_VOID:
30358a7d6542SBram Moolenaar 	    break;
30368a7d6542SBram Moolenaar     }
30378a7d6542SBram Moolenaar     return FALSE;
30388a7d6542SBram Moolenaar }
30398a7d6542SBram Moolenaar 
30408a7d6542SBram Moolenaar /*
30418a7d6542SBram Moolenaar  * If "tv" is a string give an error and return FAIL.
30428a7d6542SBram Moolenaar  */
30438a7d6542SBram Moolenaar     int
30448a7d6542SBram Moolenaar check_not_string(typval_T *tv)
30458a7d6542SBram Moolenaar {
30468a7d6542SBram Moolenaar     if (tv->v_type == VAR_STRING)
30478a7d6542SBram Moolenaar     {
30488a7d6542SBram Moolenaar 	emsg(_("E1030: Using a String as a Number"));
30498a7d6542SBram Moolenaar 	clear_tv(tv);
30508a7d6542SBram Moolenaar 	return FAIL;
30518a7d6542SBram Moolenaar     }
30528a7d6542SBram Moolenaar     return OK;
30538a7d6542SBram Moolenaar }
30548a7d6542SBram Moolenaar 
30558a7d6542SBram Moolenaar 
30568a7d6542SBram Moolenaar #endif // FEAT_EVAL
3057