xref: /vim-8.2.3635/src/vim9execute.c (revision 09689a02)
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;
131fe270817SBram 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;
1638a7d6542SBram Moolenaar 
1648a7d6542SBram Moolenaar     if (dfunc->df_deleted)
1658a7d6542SBram Moolenaar     {
1668a7d6542SBram Moolenaar 	emsg_funcname(e_func_deleted, ufunc->uf_name);
1678a7d6542SBram Moolenaar 	return FAIL;
1688a7d6542SBram Moolenaar     }
1698a7d6542SBram Moolenaar 
1701378fbc4SBram Moolenaar     if (ufunc->uf_va_name != NULL)
1711378fbc4SBram Moolenaar     {
172fe270817SBram Moolenaar 	// Need to make a list out of the vararg arguments.
1731378fbc4SBram Moolenaar 	// Stack at time of call with 2 varargs:
1741378fbc4SBram Moolenaar 	//   normal_arg
1751378fbc4SBram Moolenaar 	//   optional_arg
1761378fbc4SBram Moolenaar 	//   vararg_1
1771378fbc4SBram Moolenaar 	//   vararg_2
178fe270817SBram Moolenaar 	// After creating the list:
1791378fbc4SBram Moolenaar 	//   normal_arg
1801378fbc4SBram Moolenaar 	//   optional_arg
181fe270817SBram Moolenaar 	//   vararg-list
182fe270817SBram Moolenaar 	// With missing optional arguments we get:
183fe270817SBram Moolenaar 	//    normal_arg
184fe270817SBram Moolenaar 	// After creating the list
185fe270817SBram Moolenaar 	//    normal_arg
186fe270817SBram Moolenaar 	//    (space for optional_arg)
187fe270817SBram Moolenaar 	//    vararg-list
1881378fbc4SBram Moolenaar 	vararg_count = argcount - ufunc->uf_args.ga_len;
1891378fbc4SBram Moolenaar 	if (vararg_count < 0)
1901378fbc4SBram Moolenaar 	    vararg_count = 0;
1911378fbc4SBram Moolenaar 	else
1921378fbc4SBram Moolenaar 	    argcount -= vararg_count;
193fe270817SBram Moolenaar 	if (exe_newlist(vararg_count, ectx) == FAIL)
1941378fbc4SBram Moolenaar 	    return FAIL;
195fe270817SBram Moolenaar 
196fe270817SBram Moolenaar 	vararg_count = 1;
1971378fbc4SBram Moolenaar     }
1981378fbc4SBram Moolenaar 
199fe270817SBram Moolenaar     arg_to_add = ufunc->uf_args.ga_len - argcount;
2001378fbc4SBram Moolenaar     if (arg_to_add < 0)
2011378fbc4SBram Moolenaar     {
2021378fbc4SBram Moolenaar 	iemsg("Argument count wrong?");
2031378fbc4SBram Moolenaar 	return FAIL;
2041378fbc4SBram Moolenaar     }
205bf67ea1aSBram Moolenaar     if (ga_grow(&ectx->ec_stack, arg_to_add + 3
206bf67ea1aSBram Moolenaar 		       + dfunc->df_varcount + dfunc->df_closure_count) == FAIL)
2078a7d6542SBram Moolenaar 	return FAIL;
2088a7d6542SBram Moolenaar 
209fe270817SBram Moolenaar     // Move the vararg-list to below the missing optional arguments.
210fe270817SBram Moolenaar     if (vararg_count > 0 && arg_to_add > 0)
211fe270817SBram Moolenaar 	*STACK_TV_BOT(arg_to_add - 1) = *STACK_TV_BOT(-1);
212170fcfcfSBram Moolenaar 
213170fcfcfSBram Moolenaar     // Reserve space for omitted optional arguments, filled in soon.
2141378fbc4SBram Moolenaar     for (idx = 0; idx < arg_to_add; ++idx)
215fe270817SBram Moolenaar 	STACK_TV_BOT(idx - vararg_count)->v_type = VAR_UNKNOWN;
2161378fbc4SBram Moolenaar     ectx->ec_stack.ga_len += arg_to_add;
2178a7d6542SBram Moolenaar 
2188a7d6542SBram Moolenaar     // Store current execution state in stack frame for ISN_RETURN.
2198a7d6542SBram Moolenaar     STACK_TV_BOT(0)->vval.v_number = ectx->ec_dfunc_idx;
2208a7d6542SBram Moolenaar     STACK_TV_BOT(1)->vval.v_number = ectx->ec_iidx;
221bf67ea1aSBram Moolenaar     STACK_TV_BOT(2)->vval.v_number = ectx->ec_frame_idx;
222bf67ea1aSBram Moolenaar     ectx->ec_frame_idx = ectx->ec_stack.ga_len;
2238a7d6542SBram Moolenaar 
2248a7d6542SBram Moolenaar     // Initialize local variables
225bf67ea1aSBram Moolenaar     for (idx = 0; idx < dfunc->df_varcount + dfunc->df_closure_count; ++idx)
2268a7d6542SBram Moolenaar 	STACK_TV_BOT(STACK_FRAME_SIZE + idx)->v_type = VAR_UNKNOWN;
227bf67ea1aSBram Moolenaar     ectx->ec_stack.ga_len += STACK_FRAME_SIZE
228bf67ea1aSBram Moolenaar 				+ dfunc->df_varcount + dfunc->df_closure_count;
2298a7d6542SBram Moolenaar 
2308a7d6542SBram Moolenaar     // Set execution state to the start of the called function.
2318a7d6542SBram Moolenaar     ectx->ec_dfunc_idx = cdf_idx;
2328a7d6542SBram Moolenaar     ectx->ec_instr = dfunc->df_instr;
2338a7d6542SBram Moolenaar     estack_push_ufunc(ETYPE_UFUNC, dfunc->df_ufunc, 1);
234170fcfcfSBram Moolenaar 
235170fcfcfSBram Moolenaar     // Decide where to start execution, handles optional arguments.
236170fcfcfSBram Moolenaar     init_instr_idx(ufunc, argcount, ectx);
2378a7d6542SBram Moolenaar 
2388a7d6542SBram Moolenaar     return OK;
2398a7d6542SBram Moolenaar }
2408a7d6542SBram Moolenaar 
2418a7d6542SBram Moolenaar // Get pointer to item in the stack.
2428a7d6542SBram Moolenaar #define STACK_TV(idx) (((typval_T *)ectx->ec_stack.ga_data) + idx)
2438a7d6542SBram Moolenaar 
2448a7d6542SBram Moolenaar /*
245bf67ea1aSBram Moolenaar  * Used when returning from a function: Check if any closure is still
246bf67ea1aSBram Moolenaar  * referenced.  If so then move the arguments and variables to a separate piece
247bf67ea1aSBram Moolenaar  * of stack to be used when the closure is called.
248bf67ea1aSBram Moolenaar  * When "free_arguments" is TRUE the arguments are to be freed.
249bf67ea1aSBram Moolenaar  * Returns FAIL when out of memory.
250bf67ea1aSBram Moolenaar  */
251bf67ea1aSBram Moolenaar     static int
252bf67ea1aSBram Moolenaar handle_closure_in_use(ectx_T *ectx, int free_arguments)
253bf67ea1aSBram Moolenaar {
254bf67ea1aSBram Moolenaar     dfunc_T	*dfunc = ((dfunc_T *)def_functions.ga_data)
255bf67ea1aSBram Moolenaar 							  + ectx->ec_dfunc_idx;
256bf67ea1aSBram Moolenaar     int		argcount = ufunc_argcount(dfunc->df_ufunc);
257bf67ea1aSBram Moolenaar     int		top = ectx->ec_frame_idx - argcount;
258bf67ea1aSBram Moolenaar     int		idx;
259bf67ea1aSBram Moolenaar     typval_T	*tv;
260bf67ea1aSBram Moolenaar     int		closure_in_use = FALSE;
261bf67ea1aSBram Moolenaar 
262bf67ea1aSBram Moolenaar     // Check if any created closure is still in use.
263bf67ea1aSBram Moolenaar     for (idx = 0; idx < dfunc->df_closure_count; ++idx)
264bf67ea1aSBram Moolenaar     {
265bf67ea1aSBram Moolenaar 	tv = STACK_TV(ectx->ec_frame_idx + STACK_FRAME_SIZE
266bf67ea1aSBram Moolenaar 						   + dfunc->df_varcount + idx);
267221fcc74SBram Moolenaar 	if (tv->v_type == VAR_PARTIAL && tv->vval.v_partial != NULL
268221fcc74SBram Moolenaar 					&& tv->vval.v_partial->pt_refcount > 1)
269221fcc74SBram Moolenaar 	{
270221fcc74SBram Moolenaar 	    int refcount = tv->vval.v_partial->pt_refcount;
271221fcc74SBram Moolenaar 	    int i;
272221fcc74SBram Moolenaar 
273f821ddaaSBram Moolenaar 	    // A Reference in a local variables doesn't count, it gets
274221fcc74SBram Moolenaar 	    // unreferenced on return.
275221fcc74SBram Moolenaar 	    for (i = 0; i < dfunc->df_varcount; ++i)
276221fcc74SBram Moolenaar 	    {
277221fcc74SBram Moolenaar 		typval_T *stv = STACK_TV(ectx->ec_frame_idx
278221fcc74SBram Moolenaar 						       + STACK_FRAME_SIZE + i);
279221fcc74SBram Moolenaar 		if (stv->v_type == VAR_PARTIAL
280221fcc74SBram Moolenaar 				  && tv->vval.v_partial == stv->vval.v_partial)
281221fcc74SBram Moolenaar 		    --refcount;
282221fcc74SBram Moolenaar 	    }
283221fcc74SBram Moolenaar 	    if (refcount > 1)
284f7779c63SBram Moolenaar 	    {
285bf67ea1aSBram Moolenaar 		closure_in_use = TRUE;
286f7779c63SBram Moolenaar 		break;
287f7779c63SBram Moolenaar 	    }
288bf67ea1aSBram Moolenaar 	}
289221fcc74SBram Moolenaar     }
290bf67ea1aSBram Moolenaar 
291bf67ea1aSBram Moolenaar     if (closure_in_use)
292bf67ea1aSBram Moolenaar     {
293bf67ea1aSBram Moolenaar 	funcstack_T *funcstack = ALLOC_CLEAR_ONE(funcstack_T);
294bf67ea1aSBram Moolenaar 	typval_T    *stack;
295bf67ea1aSBram Moolenaar 
296bf67ea1aSBram Moolenaar 	// A closure is using the arguments and/or local variables.
297bf67ea1aSBram Moolenaar 	// Move them to the called function.
298bf67ea1aSBram Moolenaar 	if (funcstack == NULL)
299bf67ea1aSBram Moolenaar 	    return FAIL;
300bf67ea1aSBram Moolenaar 	funcstack->fs_ga.ga_len = argcount + STACK_FRAME_SIZE
301bf67ea1aSBram Moolenaar 							  + dfunc->df_varcount;
302bf67ea1aSBram Moolenaar 	stack = ALLOC_CLEAR_MULT(typval_T, funcstack->fs_ga.ga_len);
303bf67ea1aSBram Moolenaar 	funcstack->fs_ga.ga_data = stack;
304bf67ea1aSBram Moolenaar 	if (stack == NULL)
305bf67ea1aSBram Moolenaar 	{
306bf67ea1aSBram Moolenaar 	    vim_free(funcstack);
307bf67ea1aSBram Moolenaar 	    return FAIL;
308bf67ea1aSBram Moolenaar 	}
309bf67ea1aSBram Moolenaar 
310bf67ea1aSBram Moolenaar 	// Move or copy the arguments.
311bf67ea1aSBram Moolenaar 	for (idx = 0; idx < argcount; ++idx)
312bf67ea1aSBram Moolenaar 	{
313bf67ea1aSBram Moolenaar 	    tv = STACK_TV(top + idx);
314bf67ea1aSBram Moolenaar 	    if (free_arguments)
315bf67ea1aSBram Moolenaar 	    {
316bf67ea1aSBram Moolenaar 		*(stack + idx) = *tv;
317bf67ea1aSBram Moolenaar 		tv->v_type = VAR_UNKNOWN;
318bf67ea1aSBram Moolenaar 	    }
319bf67ea1aSBram Moolenaar 	    else
320bf67ea1aSBram Moolenaar 		copy_tv(tv, stack + idx);
321bf67ea1aSBram Moolenaar 	}
322bf67ea1aSBram Moolenaar 	// Move the local variables.
323bf67ea1aSBram Moolenaar 	for (idx = 0; idx < dfunc->df_varcount; ++idx)
324bf67ea1aSBram Moolenaar 	{
325bf67ea1aSBram Moolenaar 	    tv = STACK_TV(ectx->ec_frame_idx + STACK_FRAME_SIZE + idx);
326f821ddaaSBram Moolenaar 
327f821ddaaSBram Moolenaar 	    // Do not copy a partial created for a local function.
328f821ddaaSBram Moolenaar 	    // TODO: this won't work if the closure actually uses it.  But when
329f821ddaaSBram Moolenaar 	    // keeping it it gets complicated: it will create a reference cycle
330f821ddaaSBram Moolenaar 	    // inside the partial, thus needs special handling for garbage
331f821ddaaSBram Moolenaar 	    // collection.
332f821ddaaSBram Moolenaar 	    if (tv->v_type == VAR_PARTIAL && tv->vval.v_partial != NULL)
333f821ddaaSBram Moolenaar 	    {
334f821ddaaSBram Moolenaar 		int i;
335f821ddaaSBram Moolenaar 		typval_T *ctv;
336f821ddaaSBram Moolenaar 
337f821ddaaSBram Moolenaar 		for (i = 0; i < dfunc->df_closure_count; ++i)
338f821ddaaSBram Moolenaar 		{
339f821ddaaSBram Moolenaar 		    ctv = STACK_TV(ectx->ec_frame_idx + STACK_FRAME_SIZE
340f821ddaaSBram Moolenaar 						     + dfunc->df_varcount + i);
341f821ddaaSBram Moolenaar 		    if (tv->vval.v_partial == ctv->vval.v_partial)
342f821ddaaSBram Moolenaar 			break;
343f821ddaaSBram Moolenaar 		}
344f821ddaaSBram Moolenaar 		if (i < dfunc->df_closure_count)
345f821ddaaSBram Moolenaar 		{
346f821ddaaSBram Moolenaar 		    (stack + argcount + STACK_FRAME_SIZE + idx)->v_type =
347f821ddaaSBram Moolenaar 								   VAR_UNKNOWN;
348f821ddaaSBram Moolenaar 		    continue;
349f821ddaaSBram Moolenaar 		}
350f821ddaaSBram Moolenaar 	    }
351f821ddaaSBram Moolenaar 
352bf67ea1aSBram Moolenaar 	    *(stack + argcount + STACK_FRAME_SIZE + idx) = *tv;
353bf67ea1aSBram Moolenaar 	    tv->v_type = VAR_UNKNOWN;
354bf67ea1aSBram Moolenaar 	}
355bf67ea1aSBram Moolenaar 
356bf67ea1aSBram Moolenaar 	for (idx = 0; idx < dfunc->df_closure_count; ++idx)
357bf67ea1aSBram Moolenaar 	{
358bf67ea1aSBram Moolenaar 	    tv = STACK_TV(ectx->ec_frame_idx + STACK_FRAME_SIZE
359bf67ea1aSBram Moolenaar 						   + dfunc->df_varcount + idx);
360f7779c63SBram Moolenaar 	    if (tv->v_type == VAR_PARTIAL)
361bf67ea1aSBram Moolenaar 	    {
362f7779c63SBram Moolenaar 		partial_T *partial = tv->vval.v_partial;
363f7779c63SBram Moolenaar 
364f7779c63SBram Moolenaar 		if (partial->pt_refcount > 1)
365f7779c63SBram Moolenaar 		{
366bf67ea1aSBram Moolenaar 		    ++funcstack->fs_refcount;
367f7779c63SBram Moolenaar 		    partial->pt_funcstack = funcstack;
368f7779c63SBram Moolenaar 		    partial->pt_ectx_stack = &funcstack->fs_ga;
369f7779c63SBram Moolenaar 		    partial->pt_ectx_frame = ectx->ec_frame_idx - top;
370f7779c63SBram Moolenaar 		}
371bf67ea1aSBram Moolenaar 	    }
372bf67ea1aSBram Moolenaar 	}
373bf67ea1aSBram Moolenaar     }
374bf67ea1aSBram Moolenaar 
375bf67ea1aSBram Moolenaar     return OK;
376bf67ea1aSBram Moolenaar }
377bf67ea1aSBram Moolenaar 
378bf67ea1aSBram Moolenaar /*
3798a7d6542SBram Moolenaar  * Return from the current function.
3808a7d6542SBram Moolenaar  */
381bf67ea1aSBram Moolenaar     static int
3828a7d6542SBram Moolenaar func_return(ectx_T *ectx)
3838a7d6542SBram Moolenaar {
3848a7d6542SBram Moolenaar     int		idx;
385bf67ea1aSBram Moolenaar     dfunc_T	*dfunc = ((dfunc_T *)def_functions.ga_data)
386bf67ea1aSBram Moolenaar 							  + ectx->ec_dfunc_idx;
387bf67ea1aSBram Moolenaar     int		argcount = ufunc_argcount(dfunc->df_ufunc);
388bf67ea1aSBram Moolenaar     int		top = ectx->ec_frame_idx - argcount;
3898a7d6542SBram Moolenaar 
3908a7d6542SBram Moolenaar     // execution context goes one level up
3918a7d6542SBram Moolenaar     estack_pop();
3928a7d6542SBram Moolenaar 
393bf67ea1aSBram Moolenaar     if (handle_closure_in_use(ectx, TRUE) == FAIL)
394bf67ea1aSBram Moolenaar 	return FAIL;
395bf67ea1aSBram Moolenaar 
396bf67ea1aSBram Moolenaar     // Clear the arguments.
397bf67ea1aSBram Moolenaar     for (idx = top; idx < ectx->ec_frame_idx; ++idx)
398bf67ea1aSBram Moolenaar 	clear_tv(STACK_TV(idx));
399bf67ea1aSBram Moolenaar 
400bf67ea1aSBram Moolenaar     // Clear local variables and temp values, but not the return value.
401bf67ea1aSBram Moolenaar     for (idx = ectx->ec_frame_idx + STACK_FRAME_SIZE;
4028a7d6542SBram Moolenaar 					idx < ectx->ec_stack.ga_len - 1; ++idx)
4038a7d6542SBram Moolenaar 	clear_tv(STACK_TV(idx));
404170fcfcfSBram Moolenaar 
405170fcfcfSBram Moolenaar     // Restore the previous frame.
406bf67ea1aSBram Moolenaar     ectx->ec_dfunc_idx = STACK_TV(ectx->ec_frame_idx)->vval.v_number;
407bf67ea1aSBram Moolenaar     ectx->ec_iidx = STACK_TV(ectx->ec_frame_idx + 1)->vval.v_number;
408bf67ea1aSBram Moolenaar     ectx->ec_frame_idx = STACK_TV(ectx->ec_frame_idx + 2)->vval.v_number;
4098a7d6542SBram Moolenaar     dfunc = ((dfunc_T *)def_functions.ga_data) + ectx->ec_dfunc_idx;
4108a7d6542SBram Moolenaar     ectx->ec_instr = dfunc->df_instr;
411170fcfcfSBram Moolenaar 
412170fcfcfSBram Moolenaar     // Reset the stack to the position before the call, move the return value
413170fcfcfSBram Moolenaar     // to the top of the stack.
414170fcfcfSBram Moolenaar     idx = ectx->ec_stack.ga_len - 1;
415170fcfcfSBram Moolenaar     ectx->ec_stack.ga_len = top + 1;
416170fcfcfSBram Moolenaar     *STACK_TV_BOT(-1) = *STACK_TV(idx);
417bf67ea1aSBram Moolenaar 
418bf67ea1aSBram Moolenaar     return OK;
4198a7d6542SBram Moolenaar }
4208a7d6542SBram Moolenaar 
4218a7d6542SBram Moolenaar #undef STACK_TV
4228a7d6542SBram Moolenaar 
4238a7d6542SBram Moolenaar /*
4248a7d6542SBram Moolenaar  * Prepare arguments and rettv for calling a builtin or user function.
4258a7d6542SBram Moolenaar  */
4268a7d6542SBram Moolenaar     static int
4278a7d6542SBram Moolenaar call_prepare(int argcount, typval_T *argvars, ectx_T *ectx)
4288a7d6542SBram Moolenaar {
4298a7d6542SBram Moolenaar     int		idx;
4308a7d6542SBram Moolenaar     typval_T	*tv;
4318a7d6542SBram Moolenaar 
4328a7d6542SBram Moolenaar     // Move arguments from bottom of the stack to argvars[] and add terminator.
4338a7d6542SBram Moolenaar     for (idx = 0; idx < argcount; ++idx)
4348a7d6542SBram Moolenaar 	argvars[idx] = *STACK_TV_BOT(idx - argcount);
4358a7d6542SBram Moolenaar     argvars[argcount].v_type = VAR_UNKNOWN;
4368a7d6542SBram Moolenaar 
4378a7d6542SBram Moolenaar     // Result replaces the arguments on the stack.
4388a7d6542SBram Moolenaar     if (argcount > 0)
4398a7d6542SBram Moolenaar 	ectx->ec_stack.ga_len -= argcount - 1;
4408a7d6542SBram Moolenaar     else if (ga_grow(&ectx->ec_stack, 1) == FAIL)
4418a7d6542SBram Moolenaar 	return FAIL;
4428a7d6542SBram Moolenaar     else
4438a7d6542SBram Moolenaar 	++ectx->ec_stack.ga_len;
4448a7d6542SBram Moolenaar 
4458a7d6542SBram Moolenaar     // Default return value is zero.
4468a7d6542SBram Moolenaar     tv = STACK_TV_BOT(-1);
4478a7d6542SBram Moolenaar     tv->v_type = VAR_NUMBER;
4488a7d6542SBram Moolenaar     tv->vval.v_number = 0;
4498a7d6542SBram Moolenaar 
4508a7d6542SBram Moolenaar     return OK;
4518a7d6542SBram Moolenaar }
4528a7d6542SBram Moolenaar 
4538a7d6542SBram Moolenaar /*
4548a7d6542SBram Moolenaar  * Call a builtin function by index.
4558a7d6542SBram Moolenaar  */
4568a7d6542SBram Moolenaar     static int
4578a7d6542SBram Moolenaar call_bfunc(int func_idx, int argcount, ectx_T *ectx)
4588a7d6542SBram Moolenaar {
4598a7d6542SBram Moolenaar     typval_T	argvars[MAX_FUNC_ARGS];
4608a7d6542SBram Moolenaar     int		idx;
4618a1c1013SBram Moolenaar     int		did_emsg_before = did_emsg;
4628a7d6542SBram Moolenaar 
4638a7d6542SBram Moolenaar     if (call_prepare(argcount, argvars, ectx) == FAIL)
4648a7d6542SBram Moolenaar 	return FAIL;
4658a7d6542SBram Moolenaar 
4668a7d6542SBram Moolenaar     // Call the builtin function.
4678a7d6542SBram Moolenaar     call_internal_func_by_idx(func_idx, argvars, STACK_TV_BOT(-1));
4688a7d6542SBram Moolenaar 
4698a7d6542SBram Moolenaar     // Clear the arguments.
4708a7d6542SBram Moolenaar     for (idx = 0; idx < argcount; ++idx)
4718a7d6542SBram Moolenaar 	clear_tv(&argvars[idx]);
472015f4267SBram Moolenaar 
4738a1c1013SBram Moolenaar     if (did_emsg != did_emsg_before)
474015f4267SBram Moolenaar 	return FAIL;
4758a7d6542SBram Moolenaar     return OK;
4768a7d6542SBram Moolenaar }
4778a7d6542SBram Moolenaar 
4788a7d6542SBram Moolenaar /*
4798a7d6542SBram Moolenaar  * Execute a user defined function.
4807eeefd4aSBram Moolenaar  * "iptr" can be used to replace the instruction with a more efficient one.
4818a7d6542SBram Moolenaar  */
4828a7d6542SBram Moolenaar     static int
4837eeefd4aSBram Moolenaar call_ufunc(ufunc_T *ufunc, int argcount, ectx_T *ectx, isn_T *iptr)
4848a7d6542SBram Moolenaar {
4858a7d6542SBram Moolenaar     typval_T	argvars[MAX_FUNC_ARGS];
4868a7d6542SBram Moolenaar     funcexe_T   funcexe;
4878a7d6542SBram Moolenaar     int		error;
4888a7d6542SBram Moolenaar     int		idx;
4898a7d6542SBram Moolenaar 
4908a7d6542SBram Moolenaar     if (ufunc->uf_dfunc_idx >= 0)
4917eeefd4aSBram Moolenaar     {
4927eeefd4aSBram Moolenaar 	// The function has been compiled, can call it quickly.  For a function
4937eeefd4aSBram Moolenaar 	// that was defined later: we can call it directly next time.
4947eeefd4aSBram Moolenaar 	if (iptr != NULL)
4957eeefd4aSBram Moolenaar 	{
49620431c9dSBram Moolenaar 	    delete_instr(iptr);
4977eeefd4aSBram Moolenaar 	    iptr->isn_type = ISN_DCALL;
4987eeefd4aSBram Moolenaar 	    iptr->isn_arg.dfunc.cdf_idx = ufunc->uf_dfunc_idx;
4997eeefd4aSBram Moolenaar 	    iptr->isn_arg.dfunc.cdf_argcount = argcount;
5007eeefd4aSBram Moolenaar 	}
5018a7d6542SBram Moolenaar 	return call_dfunc(ufunc->uf_dfunc_idx, argcount, ectx);
5027eeefd4aSBram Moolenaar     }
5038a7d6542SBram Moolenaar 
5048a7d6542SBram Moolenaar     if (call_prepare(argcount, argvars, ectx) == FAIL)
5058a7d6542SBram Moolenaar 	return FAIL;
506a80faa89SBram Moolenaar     CLEAR_FIELD(funcexe);
5078a7d6542SBram Moolenaar     funcexe.evaluate = TRUE;
5088a7d6542SBram Moolenaar 
5098a7d6542SBram Moolenaar     // Call the user function.  Result goes in last position on the stack.
5108a7d6542SBram Moolenaar     // TODO: add selfdict if there is one
5118a7d6542SBram Moolenaar     error = call_user_func_check(ufunc, argcount, argvars,
5128a7d6542SBram Moolenaar 					     STACK_TV_BOT(-1), &funcexe, NULL);
5138a7d6542SBram Moolenaar 
5148a7d6542SBram Moolenaar     // Clear the arguments.
5158a7d6542SBram Moolenaar     for (idx = 0; idx < argcount; ++idx)
5168a7d6542SBram Moolenaar 	clear_tv(&argvars[idx]);
5178a7d6542SBram Moolenaar 
5188a7d6542SBram Moolenaar     if (error != FCERR_NONE)
5198a7d6542SBram Moolenaar     {
5208a7d6542SBram Moolenaar 	user_func_error(error, ufunc->uf_name);
5218a7d6542SBram Moolenaar 	return FAIL;
5228a7d6542SBram Moolenaar     }
5238a7d6542SBram Moolenaar     return OK;
5248a7d6542SBram Moolenaar }
5258a7d6542SBram Moolenaar 
5268a7d6542SBram Moolenaar /*
5278a7d6542SBram Moolenaar  * Execute a function by "name".
5288a7d6542SBram Moolenaar  * This can be a builtin function or a user function.
5297eeefd4aSBram Moolenaar  * "iptr" can be used to replace the instruction with a more efficient one.
5308a7d6542SBram Moolenaar  * Returns FAIL if not found without an error message.
5318a7d6542SBram Moolenaar  */
5328a7d6542SBram Moolenaar     static int
5337eeefd4aSBram Moolenaar call_by_name(char_u *name, int argcount, ectx_T *ectx, isn_T *iptr)
5348a7d6542SBram Moolenaar {
5358a7d6542SBram Moolenaar     ufunc_T *ufunc;
5368a7d6542SBram Moolenaar 
5378a7d6542SBram Moolenaar     if (builtin_function(name, -1))
5388a7d6542SBram Moolenaar     {
5398a7d6542SBram Moolenaar 	int func_idx = find_internal_func(name);
5408a7d6542SBram Moolenaar 
5418a7d6542SBram Moolenaar 	if (func_idx < 0)
5428a7d6542SBram Moolenaar 	    return FAIL;
5438a7d6542SBram Moolenaar 	if (check_internal_func(func_idx, argcount) == FAIL)
5448a7d6542SBram Moolenaar 	    return FAIL;
5458a7d6542SBram Moolenaar 	return call_bfunc(func_idx, argcount, ectx);
5468a7d6542SBram Moolenaar     }
5478a7d6542SBram Moolenaar 
5484c17ad94SBram Moolenaar     ufunc = find_func(name, FALSE, NULL);
5498a7d6542SBram Moolenaar     if (ufunc != NULL)
5507eeefd4aSBram Moolenaar 	return call_ufunc(ufunc, argcount, ectx, iptr);
5518a7d6542SBram Moolenaar 
5528a7d6542SBram Moolenaar     return FAIL;
5538a7d6542SBram Moolenaar }
5548a7d6542SBram Moolenaar 
5558a7d6542SBram Moolenaar     static int
5568a7d6542SBram Moolenaar call_partial(typval_T *tv, int argcount, ectx_T *ectx)
5578a7d6542SBram Moolenaar {
558bd5da371SBram Moolenaar     char_u	*name = NULL;
5598a7d6542SBram Moolenaar     int		called_emsg_before = called_emsg;
5608a7d6542SBram Moolenaar 
5618a7d6542SBram Moolenaar     if (tv->v_type == VAR_PARTIAL)
5628a7d6542SBram Moolenaar     {
5638a7d6542SBram Moolenaar 	partial_T *pt = tv->vval.v_partial;
5648a7d6542SBram Moolenaar 
5658a7d6542SBram Moolenaar 	if (pt->pt_func != NULL)
566f7779c63SBram Moolenaar 	{
567f7779c63SBram Moolenaar 	    int ret = call_ufunc(pt->pt_func, argcount, ectx, NULL);
568f7779c63SBram Moolenaar 
569f7779c63SBram Moolenaar 	    // closure may need the function context where it was defined
570f7779c63SBram Moolenaar 	    ectx->ec_outer_stack = pt->pt_ectx_stack;
571f7779c63SBram Moolenaar 	    ectx->ec_outer_frame = pt->pt_ectx_frame;
572f7779c63SBram Moolenaar 
573f7779c63SBram Moolenaar 	    return ret;
574f7779c63SBram Moolenaar 	}
5758a7d6542SBram Moolenaar 	name = pt->pt_name;
5768a7d6542SBram Moolenaar     }
577bd5da371SBram Moolenaar     else if (tv->v_type == VAR_FUNC)
5788a7d6542SBram Moolenaar 	name = tv->vval.v_string;
579bd5da371SBram Moolenaar     if (name == NULL || call_by_name(name, argcount, ectx, NULL) == FAIL)
5808a7d6542SBram Moolenaar     {
5818a7d6542SBram Moolenaar 	if (called_emsg == called_emsg_before)
582015f4267SBram Moolenaar 	    semsg(_(e_unknownfunc),
583015f4267SBram Moolenaar 				  name == NULL ? (char_u *)"[unknown]" : name);
5848a7d6542SBram Moolenaar 	return FAIL;
5858a7d6542SBram Moolenaar     }
5868a7d6542SBram Moolenaar     return OK;
5878a7d6542SBram Moolenaar }
5888a7d6542SBram Moolenaar 
5898a7d6542SBram Moolenaar /*
5900bbf722aSBram Moolenaar  * Store "tv" in variable "name".
5910bbf722aSBram Moolenaar  * This is for s: and g: variables.
5920bbf722aSBram Moolenaar  */
5930bbf722aSBram Moolenaar     static void
5940bbf722aSBram Moolenaar store_var(char_u *name, typval_T *tv)
5950bbf722aSBram Moolenaar {
5960bbf722aSBram Moolenaar     funccal_entry_T entry;
5970bbf722aSBram Moolenaar 
5980bbf722aSBram Moolenaar     save_funccal(&entry);
5995deeb3f1SBram Moolenaar     set_var_const(name, NULL, tv, FALSE, LET_NO_COMMAND);
6000bbf722aSBram Moolenaar     restore_funccal();
6010bbf722aSBram Moolenaar }
6020bbf722aSBram Moolenaar 
603d3aac291SBram Moolenaar 
6040bbf722aSBram Moolenaar /*
6058a7d6542SBram Moolenaar  * Execute a function by "name".
6068a7d6542SBram Moolenaar  * This can be a builtin function, user function or a funcref.
6077eeefd4aSBram Moolenaar  * "iptr" can be used to replace the instruction with a more efficient one.
6088a7d6542SBram Moolenaar  */
6098a7d6542SBram Moolenaar     static int
6107eeefd4aSBram Moolenaar call_eval_func(char_u *name, int argcount, ectx_T *ectx, isn_T *iptr)
6118a7d6542SBram Moolenaar {
6128a7d6542SBram Moolenaar     int		called_emsg_before = called_emsg;
6138a7d6542SBram Moolenaar 
6147eeefd4aSBram Moolenaar     if (call_by_name(name, argcount, ectx, iptr) == FAIL
6158a7d6542SBram Moolenaar 					  && called_emsg == called_emsg_before)
6168a7d6542SBram Moolenaar     {
6171df8b3fbSBram Moolenaar 	dictitem_T	*v;
6181df8b3fbSBram Moolenaar 
6191df8b3fbSBram Moolenaar 	v = find_var(name, NULL, FALSE);
6201df8b3fbSBram Moolenaar 	if (v == NULL)
6211df8b3fbSBram Moolenaar 	{
6221df8b3fbSBram Moolenaar 	    semsg(_(e_unknownfunc), name);
6238a7d6542SBram Moolenaar 	    return FAIL;
6248a7d6542SBram Moolenaar 	}
6251df8b3fbSBram Moolenaar 	if (v->di_tv.v_type != VAR_PARTIAL && v->di_tv.v_type != VAR_FUNC)
6261df8b3fbSBram Moolenaar 	{
6271df8b3fbSBram Moolenaar 	    semsg(_(e_unknownfunc), name);
6281df8b3fbSBram Moolenaar 	    return FAIL;
6291df8b3fbSBram Moolenaar 	}
6301df8b3fbSBram Moolenaar 	return call_partial(&v->di_tv, argcount, ectx);
6311df8b3fbSBram Moolenaar     }
6328a7d6542SBram Moolenaar     return OK;
6338a7d6542SBram Moolenaar }
6348a7d6542SBram Moolenaar 
6358a7d6542SBram Moolenaar /*
6368a7d6542SBram Moolenaar  * Call a "def" function from old Vim script.
6378a7d6542SBram Moolenaar  * Return OK or FAIL.
6388a7d6542SBram Moolenaar  */
6398a7d6542SBram Moolenaar     int
6408a7d6542SBram Moolenaar call_def_function(
6418a7d6542SBram Moolenaar     ufunc_T	*ufunc,
64223e03252SBram Moolenaar     int		argc_arg,	// nr of arguments
6438a7d6542SBram Moolenaar     typval_T	*argv,		// arguments
6448a7d6542SBram Moolenaar     typval_T	*rettv)		// return value
6458a7d6542SBram Moolenaar {
6468a7d6542SBram Moolenaar     ectx_T	ectx;		// execution context
64723e03252SBram Moolenaar     int		argc = argc_arg;
648bf67ea1aSBram Moolenaar     int		initial_frame_idx;
6498a7d6542SBram Moolenaar     typval_T	*tv;
6508a7d6542SBram Moolenaar     int		idx;
6518a7d6542SBram Moolenaar     int		ret = FAIL;
652170fcfcfSBram Moolenaar     int		defcount = ufunc->uf_args.ga_len - argc;
653a26b9700SBram Moolenaar     int		save_sc_version = current_sctx.sc_version;
6548a7d6542SBram Moolenaar 
6558a7d6542SBram Moolenaar // Get pointer to item in the stack.
6568a7d6542SBram Moolenaar #define STACK_TV(idx) (((typval_T *)ectx.ec_stack.ga_data) + idx)
6578a7d6542SBram Moolenaar 
6588a7d6542SBram Moolenaar // Get pointer to item at the bottom of the stack, -1 is the bottom.
6598a7d6542SBram Moolenaar #undef STACK_TV_BOT
6608a7d6542SBram Moolenaar #define STACK_TV_BOT(idx) (((typval_T *)ectx.ec_stack.ga_data) + ectx.ec_stack.ga_len + idx)
6618a7d6542SBram Moolenaar 
6621378fbc4SBram Moolenaar // Get pointer to a local variable on the stack.  Negative for arguments.
663bf67ea1aSBram Moolenaar #define STACK_TV_VAR(idx) (((typval_T *)ectx.ec_stack.ga_data) + ectx.ec_frame_idx + STACK_FRAME_SIZE + idx)
6648a7d6542SBram Moolenaar 
665c8cd2b34SBram Moolenaar // Like STACK_TV_VAR but use the outer scope
666c8cd2b34SBram Moolenaar #define STACK_OUT_TV_VAR(idx) (((typval_T *)ectx.ec_outer_stack->ga_data) + ectx.ec_outer_frame + STACK_FRAME_SIZE + idx)
667c8cd2b34SBram Moolenaar 
668a80faa89SBram Moolenaar     CLEAR_FIELD(ectx);
6698a7d6542SBram Moolenaar     ga_init2(&ectx.ec_stack, sizeof(typval_T), 500);
6708a7d6542SBram Moolenaar     if (ga_grow(&ectx.ec_stack, 20) == FAIL)
671d5aec0ceSBram Moolenaar 	return FAIL;
672*09689a02SBram Moolenaar     {
673*09689a02SBram Moolenaar 	// Check the function was compiled, it is postponed in ex_vim9script().
674*09689a02SBram Moolenaar 	dfunc_T	*dfunc = ((dfunc_T *)def_functions.ga_data)
675*09689a02SBram Moolenaar 							 + ufunc->uf_dfunc_idx;
676*09689a02SBram Moolenaar 	if (dfunc->df_instr == NULL)
677*09689a02SBram Moolenaar 	    return FAIL;
678*09689a02SBram Moolenaar     }
6798a7d6542SBram Moolenaar     ectx.ec_dfunc_idx = ufunc->uf_dfunc_idx;
6808a7d6542SBram Moolenaar 
6818a7d6542SBram Moolenaar     ga_init2(&ectx.ec_trystack, sizeof(trycmd_T), 10);
6828a7d6542SBram Moolenaar 
6838a7d6542SBram Moolenaar     // Put arguments on the stack.
6848a7d6542SBram Moolenaar     for (idx = 0; idx < argc; ++idx)
6858a7d6542SBram Moolenaar     {
6868a7d6542SBram Moolenaar 	copy_tv(&argv[idx], STACK_TV_BOT(0));
6878a7d6542SBram Moolenaar 	++ectx.ec_stack.ga_len;
6888a7d6542SBram Moolenaar     }
68923e03252SBram Moolenaar 
69023e03252SBram Moolenaar     // Turn varargs into a list.  Empty list if no args.
69123e03252SBram Moolenaar     if (ufunc->uf_va_name != NULL)
69223e03252SBram Moolenaar     {
69323e03252SBram Moolenaar 	int vararg_count = argc - ufunc->uf_args.ga_len;
69423e03252SBram Moolenaar 
69523e03252SBram Moolenaar 	if (vararg_count < 0)
69623e03252SBram Moolenaar 	    vararg_count = 0;
69723e03252SBram Moolenaar 	else
69823e03252SBram Moolenaar 	    argc -= vararg_count;
69923e03252SBram Moolenaar 	if (exe_newlist(vararg_count, &ectx) == FAIL)
7001a2f4bf6SBram Moolenaar 	    goto failed_early;
70123e03252SBram Moolenaar 	if (defcount > 0)
70223e03252SBram Moolenaar 	    // Move varargs list to below missing default arguments.
70323e03252SBram Moolenaar 	    *STACK_TV_BOT(defcount- 1) = *STACK_TV_BOT(-1);
70423e03252SBram Moolenaar 	--ectx.ec_stack.ga_len;
70523e03252SBram Moolenaar     }
70623e03252SBram Moolenaar 
707170fcfcfSBram Moolenaar     // Make space for omitted arguments, will store default value below.
70823e03252SBram Moolenaar     // Any varargs list goes after them.
709170fcfcfSBram Moolenaar     if (defcount > 0)
710170fcfcfSBram Moolenaar 	for (idx = 0; idx < defcount; ++idx)
711170fcfcfSBram Moolenaar 	{
712170fcfcfSBram Moolenaar 	    STACK_TV_BOT(0)->v_type = VAR_UNKNOWN;
713170fcfcfSBram Moolenaar 	    ++ectx.ec_stack.ga_len;
714170fcfcfSBram Moolenaar 	}
71523e03252SBram Moolenaar     if (ufunc->uf_va_name != NULL)
71623e03252SBram Moolenaar 	    ++ectx.ec_stack.ga_len;
7178a7d6542SBram Moolenaar 
7188a7d6542SBram Moolenaar     // Frame pointer points to just after arguments.
719bf67ea1aSBram Moolenaar     ectx.ec_frame_idx = ectx.ec_stack.ga_len;
720bf67ea1aSBram Moolenaar     initial_frame_idx = ectx.ec_frame_idx;
7218a7d6542SBram Moolenaar 
7228a7d6542SBram Moolenaar     // dummy frame entries
7238a7d6542SBram Moolenaar     for (idx = 0; idx < STACK_FRAME_SIZE; ++idx)
7248a7d6542SBram Moolenaar     {
7258a7d6542SBram Moolenaar 	STACK_TV(ectx.ec_stack.ga_len)->v_type = VAR_UNKNOWN;
7268a7d6542SBram Moolenaar 	++ectx.ec_stack.ga_len;
7278a7d6542SBram Moolenaar     }
7288a7d6542SBram Moolenaar 
729bd5da371SBram Moolenaar     {
730bf67ea1aSBram Moolenaar 	// Reserve space for local variables and closure references.
731bd5da371SBram Moolenaar 	dfunc_T	*dfunc = ((dfunc_T *)def_functions.ga_data)
732bd5da371SBram Moolenaar 							 + ufunc->uf_dfunc_idx;
733bf67ea1aSBram Moolenaar 	int	count = dfunc->df_varcount + dfunc->df_closure_count;
734bd5da371SBram Moolenaar 
735bf67ea1aSBram Moolenaar 	for (idx = 0; idx < count; ++idx)
7368a7d6542SBram Moolenaar 	    STACK_TV_VAR(idx)->v_type = VAR_UNKNOWN;
737bf67ea1aSBram Moolenaar 	ectx.ec_stack.ga_len += count;
7388a7d6542SBram Moolenaar 
7398a7d6542SBram Moolenaar 	ectx.ec_instr = dfunc->df_instr;
740bd5da371SBram Moolenaar     }
741170fcfcfSBram Moolenaar 
742a26b9700SBram Moolenaar     // Commands behave like vim9script.
743a26b9700SBram Moolenaar     current_sctx.sc_version = SCRIPT_VERSION_VIM9;
744a26b9700SBram Moolenaar 
745170fcfcfSBram Moolenaar     // Decide where to start execution, handles optional arguments.
746170fcfcfSBram Moolenaar     init_instr_idx(ufunc, argc, &ectx);
747170fcfcfSBram Moolenaar 
7488a7d6542SBram Moolenaar     for (;;)
7498a7d6542SBram Moolenaar     {
7508a7d6542SBram Moolenaar 	isn_T	    *iptr;
75120431c9dSBram Moolenaar 
75220431c9dSBram Moolenaar 	veryfast_breakcheck();
75320431c9dSBram Moolenaar 	if (got_int)
75420431c9dSBram Moolenaar 	{
75520431c9dSBram Moolenaar 	    // Turn CTRL-C into an exception.
75620431c9dSBram Moolenaar 	    got_int = FALSE;
75797acfc78SBram Moolenaar 	    if (throw_exception("Vim:Interrupt", ET_INTERRUPT, NULL) == FAIL)
75820431c9dSBram Moolenaar 		goto failed;
75920431c9dSBram Moolenaar 	    did_throw = TRUE;
76020431c9dSBram Moolenaar 	}
7618a7d6542SBram Moolenaar 
762a26b9700SBram Moolenaar 	if (did_emsg && msg_list != NULL && *msg_list != NULL)
763a26b9700SBram Moolenaar 	{
764a26b9700SBram Moolenaar 	    // Turn an error message into an exception.
765a26b9700SBram Moolenaar 	    did_emsg = FALSE;
766a26b9700SBram Moolenaar 	    if (throw_exception(*msg_list, ET_ERROR, NULL) == FAIL)
767a26b9700SBram Moolenaar 		goto failed;
768a26b9700SBram Moolenaar 	    did_throw = TRUE;
769a26b9700SBram Moolenaar 	    *msg_list = NULL;
770a26b9700SBram Moolenaar 	}
771a26b9700SBram Moolenaar 
7728a7d6542SBram Moolenaar 	if (did_throw && !ectx.ec_in_catch)
7738a7d6542SBram Moolenaar 	{
7748a7d6542SBram Moolenaar 	    garray_T	*trystack = &ectx.ec_trystack;
77520431c9dSBram Moolenaar 	    trycmd_T    *trycmd = NULL;
7768a7d6542SBram Moolenaar 
7778a7d6542SBram Moolenaar 	    // An exception jumps to the first catch, finally, or returns from
7788a7d6542SBram Moolenaar 	    // the current function.
7798a7d6542SBram Moolenaar 	    if (trystack->ga_len > 0)
7808a7d6542SBram Moolenaar 		trycmd = ((trycmd_T *)trystack->ga_data) + trystack->ga_len - 1;
781bf67ea1aSBram Moolenaar 	    if (trycmd != NULL && trycmd->tcd_frame_idx == ectx.ec_frame_idx)
7828a7d6542SBram Moolenaar 	    {
7838a7d6542SBram Moolenaar 		// jump to ":catch" or ":finally"
7848a7d6542SBram Moolenaar 		ectx.ec_in_catch = TRUE;
7858a7d6542SBram Moolenaar 		ectx.ec_iidx = trycmd->tcd_catch_idx;
7868a7d6542SBram Moolenaar 	    }
7878a7d6542SBram Moolenaar 	    else
7888a7d6542SBram Moolenaar 	    {
7898a7d6542SBram Moolenaar 		// not inside try or need to return from current functions.
790bf67ea1aSBram Moolenaar 		if (ectx.ec_frame_idx == initial_frame_idx)
7918a7d6542SBram Moolenaar 		{
7928a7d6542SBram Moolenaar 		    // At the toplevel we are done.  Push a dummy return value.
7938a7d6542SBram Moolenaar 		    if (ga_grow(&ectx.ec_stack, 1) == FAIL)
7948a7d6542SBram Moolenaar 			goto failed;
7958a7d6542SBram Moolenaar 		    tv = STACK_TV_BOT(0);
7968a7d6542SBram Moolenaar 		    tv->v_type = VAR_NUMBER;
7978a7d6542SBram Moolenaar 		    tv->vval.v_number = 0;
7988a7d6542SBram Moolenaar 		    ++ectx.ec_stack.ga_len;
799257cc5eeSBram Moolenaar 		    need_rethrow = TRUE;
800bf67ea1aSBram Moolenaar 		    if (handle_closure_in_use(&ectx, FALSE) == FAIL)
801bf67ea1aSBram Moolenaar 			goto failed;
8028a7d6542SBram Moolenaar 		    goto done;
8038a7d6542SBram Moolenaar 		}
8048a7d6542SBram Moolenaar 
805bf67ea1aSBram Moolenaar 		if (func_return(&ectx) == FAIL)
806bf67ea1aSBram Moolenaar 		    goto failed;
8078a7d6542SBram Moolenaar 	    }
8088a7d6542SBram Moolenaar 	    continue;
8098a7d6542SBram Moolenaar 	}
8108a7d6542SBram Moolenaar 
8118a7d6542SBram Moolenaar 	iptr = &ectx.ec_instr[ectx.ec_iidx++];
8128a7d6542SBram Moolenaar 	switch (iptr->isn_type)
8138a7d6542SBram Moolenaar 	{
8148a7d6542SBram Moolenaar 	    // execute Ex command line
8158a7d6542SBram Moolenaar 	    case ISN_EXEC:
8166378c4feSBram Moolenaar 		SOURCING_LNUM = iptr->isn_lnum;
8178a7d6542SBram Moolenaar 		do_cmdline_cmd(iptr->isn_arg.string);
8188a7d6542SBram Moolenaar 		break;
8198a7d6542SBram Moolenaar 
820cfe435d7SBram Moolenaar 	    // execute Ex command from pieces on the stack
821cfe435d7SBram Moolenaar 	    case ISN_EXECCONCAT:
822cfe435d7SBram Moolenaar 		{
823cfe435d7SBram Moolenaar 		    int	    count = iptr->isn_arg.number;
8247f6f56f4SBram Moolenaar 		    size_t  len = 0;
825cfe435d7SBram Moolenaar 		    int	    pass;
826cfe435d7SBram Moolenaar 		    int	    i;
827cfe435d7SBram Moolenaar 		    char_u  *cmd = NULL;
828cfe435d7SBram Moolenaar 		    char_u  *str;
829cfe435d7SBram Moolenaar 
830cfe435d7SBram Moolenaar 		    for (pass = 1; pass <= 2; ++pass)
831cfe435d7SBram Moolenaar 		    {
832cfe435d7SBram Moolenaar 			for (i = 0; i < count; ++i)
833cfe435d7SBram Moolenaar 			{
834cfe435d7SBram Moolenaar 			    tv = STACK_TV_BOT(i - count);
835cfe435d7SBram Moolenaar 			    str = tv->vval.v_string;
836cfe435d7SBram Moolenaar 			    if (str != NULL && *str != NUL)
837cfe435d7SBram Moolenaar 			    {
838cfe435d7SBram Moolenaar 				if (pass == 2)
839cfe435d7SBram Moolenaar 				    STRCPY(cmd + len, str);
840cfe435d7SBram Moolenaar 				len += STRLEN(str);
841cfe435d7SBram Moolenaar 			    }
842cfe435d7SBram Moolenaar 			    if (pass == 2)
843cfe435d7SBram Moolenaar 				clear_tv(tv);
844cfe435d7SBram Moolenaar 			}
845cfe435d7SBram Moolenaar 			if (pass == 1)
846cfe435d7SBram Moolenaar 			{
847cfe435d7SBram Moolenaar 			    cmd = alloc(len + 1);
848cfe435d7SBram Moolenaar 			    if (cmd == NULL)
849cfe435d7SBram Moolenaar 				goto failed;
850cfe435d7SBram Moolenaar 			    len = 0;
851cfe435d7SBram Moolenaar 			}
852cfe435d7SBram Moolenaar 		    }
853cfe435d7SBram Moolenaar 
8546378c4feSBram Moolenaar 		    SOURCING_LNUM = iptr->isn_lnum;
855cfe435d7SBram Moolenaar 		    do_cmdline_cmd(cmd);
856cfe435d7SBram Moolenaar 		    vim_free(cmd);
857cfe435d7SBram Moolenaar 		}
858cfe435d7SBram Moolenaar 		break;
859cfe435d7SBram Moolenaar 
8608a7d6542SBram Moolenaar 	    // execute :echo {string} ...
8618a7d6542SBram Moolenaar 	    case ISN_ECHO:
8628a7d6542SBram Moolenaar 		{
8638a7d6542SBram Moolenaar 		    int count = iptr->isn_arg.echo.echo_count;
8648a7d6542SBram Moolenaar 		    int	atstart = TRUE;
8658a7d6542SBram Moolenaar 		    int needclr = TRUE;
8668a7d6542SBram Moolenaar 
8678a7d6542SBram Moolenaar 		    for (idx = 0; idx < count; ++idx)
8688a7d6542SBram Moolenaar 		    {
8698a7d6542SBram Moolenaar 			tv = STACK_TV_BOT(idx - count);
8708a7d6542SBram Moolenaar 			echo_one(tv, iptr->isn_arg.echo.echo_with_white,
8718a7d6542SBram Moolenaar 							   &atstart, &needclr);
8728a7d6542SBram Moolenaar 			clear_tv(tv);
8738a7d6542SBram Moolenaar 		    }
874e0807ea4SBram Moolenaar 		    if (needclr)
875e0807ea4SBram Moolenaar 			msg_clr_eos();
8768a7d6542SBram Moolenaar 		    ectx.ec_stack.ga_len -= count;
8778a7d6542SBram Moolenaar 		}
8788a7d6542SBram Moolenaar 		break;
8798a7d6542SBram Moolenaar 
880f93c7feaSBram Moolenaar 	    // :execute {string} ...
881f93c7feaSBram Moolenaar 	    // :echomsg {string} ...
882f93c7feaSBram Moolenaar 	    // :echoerr {string} ...
883ad39c094SBram Moolenaar 	    case ISN_EXECUTE:
884f93c7feaSBram Moolenaar 	    case ISN_ECHOMSG:
885f93c7feaSBram Moolenaar 	    case ISN_ECHOERR:
886ad39c094SBram Moolenaar 		{
887ad39c094SBram Moolenaar 		    int		count = iptr->isn_arg.number;
888ad39c094SBram Moolenaar 		    garray_T	ga;
889ad39c094SBram Moolenaar 		    char_u	buf[NUMBUFLEN];
890ad39c094SBram Moolenaar 		    char_u	*p;
891ad39c094SBram Moolenaar 		    int		len;
892ad39c094SBram Moolenaar 		    int		failed = FALSE;
893ad39c094SBram Moolenaar 
894ad39c094SBram Moolenaar 		    ga_init2(&ga, 1, 80);
895ad39c094SBram Moolenaar 		    for (idx = 0; idx < count; ++idx)
896ad39c094SBram Moolenaar 		    {
897ad39c094SBram Moolenaar 			tv = STACK_TV_BOT(idx - count);
898ad39c094SBram Moolenaar 			if (tv->v_type == VAR_CHANNEL || tv->v_type == VAR_JOB)
899ad39c094SBram Moolenaar 			{
900ad39c094SBram Moolenaar 			    emsg(_(e_inval_string));
901ad39c094SBram Moolenaar 			    break;
902ad39c094SBram Moolenaar 			}
903ad39c094SBram Moolenaar 			else
904ad39c094SBram Moolenaar 			    p = tv_get_string_buf(tv, buf);
905ad39c094SBram Moolenaar 
906ad39c094SBram Moolenaar 			len = (int)STRLEN(p);
907ad39c094SBram Moolenaar 			if (ga_grow(&ga, len + 2) == FAIL)
908ad39c094SBram Moolenaar 			    failed = TRUE;
909ad39c094SBram Moolenaar 			else
910ad39c094SBram Moolenaar 			{
911ad39c094SBram Moolenaar 			    if (ga.ga_len > 0)
912ad39c094SBram Moolenaar 				((char_u *)(ga.ga_data))[ga.ga_len++] = ' ';
913ad39c094SBram Moolenaar 			    STRCPY((char_u *)(ga.ga_data) + ga.ga_len, p);
914ad39c094SBram Moolenaar 			    ga.ga_len += len;
915ad39c094SBram Moolenaar 			}
916ad39c094SBram Moolenaar 			clear_tv(tv);
917ad39c094SBram Moolenaar 		    }
918ad39c094SBram Moolenaar 		    ectx.ec_stack.ga_len -= count;
919ad39c094SBram Moolenaar 
920ad39c094SBram Moolenaar 		    if (!failed && ga.ga_data != NULL)
921f93c7feaSBram Moolenaar 		    {
922f93c7feaSBram Moolenaar 			if (iptr->isn_type == ISN_EXECUTE)
923ad39c094SBram Moolenaar 			    do_cmdline_cmd((char_u *)ga.ga_data);
924f93c7feaSBram Moolenaar 			else
925f93c7feaSBram Moolenaar 			{
926f93c7feaSBram Moolenaar 			    msg_sb_eol();
927f93c7feaSBram Moolenaar 			    if (iptr->isn_type == ISN_ECHOMSG)
928f93c7feaSBram Moolenaar 			    {
929f93c7feaSBram Moolenaar 				msg_attr(ga.ga_data, echo_attr);
930f93c7feaSBram Moolenaar 				out_flush();
931f93c7feaSBram Moolenaar 			    }
932f93c7feaSBram Moolenaar 			    else
933f93c7feaSBram Moolenaar 			    {
934f93c7feaSBram Moolenaar 				SOURCING_LNUM = iptr->isn_lnum;
935f93c7feaSBram Moolenaar 				emsg(ga.ga_data);
936f93c7feaSBram Moolenaar 			    }
937f93c7feaSBram Moolenaar 			}
938f93c7feaSBram Moolenaar 		    }
939ad39c094SBram Moolenaar 		    ga_clear(&ga);
940ad39c094SBram Moolenaar 		}
941ad39c094SBram Moolenaar 		break;
942ad39c094SBram Moolenaar 
9438a7d6542SBram Moolenaar 	    // load local variable or argument
9448a7d6542SBram Moolenaar 	    case ISN_LOAD:
9458a7d6542SBram Moolenaar 		if (ga_grow(&ectx.ec_stack, 1) == FAIL)
9468a7d6542SBram Moolenaar 		    goto failed;
9478a7d6542SBram Moolenaar 		copy_tv(STACK_TV_VAR(iptr->isn_arg.number), STACK_TV_BOT(0));
9488a7d6542SBram Moolenaar 		++ectx.ec_stack.ga_len;
9498a7d6542SBram Moolenaar 		break;
9508a7d6542SBram Moolenaar 
951c8cd2b34SBram Moolenaar 	    // load variable or argument from outer scope
952c8cd2b34SBram Moolenaar 	    case ISN_LOADOUTER:
953c8cd2b34SBram Moolenaar 		if (ga_grow(&ectx.ec_stack, 1) == FAIL)
954c8cd2b34SBram Moolenaar 		    goto failed;
955c8cd2b34SBram Moolenaar 		copy_tv(STACK_OUT_TV_VAR(iptr->isn_arg.number),
956c8cd2b34SBram Moolenaar 							      STACK_TV_BOT(0));
957c8cd2b34SBram Moolenaar 		++ectx.ec_stack.ga_len;
958c8cd2b34SBram Moolenaar 		break;
959c8cd2b34SBram Moolenaar 
9608a7d6542SBram Moolenaar 	    // load v: variable
9618a7d6542SBram Moolenaar 	    case ISN_LOADV:
9628a7d6542SBram Moolenaar 		if (ga_grow(&ectx.ec_stack, 1) == FAIL)
9638a7d6542SBram Moolenaar 		    goto failed;
9648a7d6542SBram Moolenaar 		copy_tv(get_vim_var_tv(iptr->isn_arg.number), STACK_TV_BOT(0));
9658a7d6542SBram Moolenaar 		++ectx.ec_stack.ga_len;
9668a7d6542SBram Moolenaar 		break;
9678a7d6542SBram Moolenaar 
968b283a8a6SBram Moolenaar 	    // load s: variable in Vim9 script
9698a7d6542SBram Moolenaar 	    case ISN_LOADSCRIPT:
9708a7d6542SBram Moolenaar 		{
9718a7d6542SBram Moolenaar 		    scriptitem_T *si =
97221b9e977SBram Moolenaar 				  SCRIPT_ITEM(iptr->isn_arg.script.script_sid);
9738a7d6542SBram Moolenaar 		    svar_T	 *sv;
9748a7d6542SBram Moolenaar 
9758a7d6542SBram Moolenaar 		    sv = ((svar_T *)si->sn_var_vals.ga_data)
9768a7d6542SBram Moolenaar 					     + iptr->isn_arg.script.script_idx;
9778a7d6542SBram Moolenaar 		    if (ga_grow(&ectx.ec_stack, 1) == FAIL)
9788a7d6542SBram Moolenaar 			goto failed;
9798a7d6542SBram Moolenaar 		    copy_tv(sv->sv_tv, STACK_TV_BOT(0));
9808a7d6542SBram Moolenaar 		    ++ectx.ec_stack.ga_len;
9818a7d6542SBram Moolenaar 		}
9828a7d6542SBram Moolenaar 		break;
9838a7d6542SBram Moolenaar 
9848a7d6542SBram Moolenaar 	    // load s: variable in old script
9858a7d6542SBram Moolenaar 	    case ISN_LOADS:
9868a7d6542SBram Moolenaar 		{
987b283a8a6SBram Moolenaar 		    hashtab_T	*ht = &SCRIPT_VARS(
988b283a8a6SBram Moolenaar 					       iptr->isn_arg.loadstore.ls_sid);
989b283a8a6SBram Moolenaar 		    char_u	*name = iptr->isn_arg.loadstore.ls_name;
9908a7d6542SBram Moolenaar 		    dictitem_T	*di = find_var_in_ht(ht, 0, name, TRUE);
9910bbf722aSBram Moolenaar 
9928a7d6542SBram Moolenaar 		    if (di == NULL)
9938a7d6542SBram Moolenaar 		    {
994b283a8a6SBram Moolenaar 			semsg(_(e_undefvar), name);
9958a7d6542SBram Moolenaar 			goto failed;
9968a7d6542SBram Moolenaar 		    }
9978a7d6542SBram Moolenaar 		    else
9988a7d6542SBram Moolenaar 		    {
9998a7d6542SBram Moolenaar 			if (ga_grow(&ectx.ec_stack, 1) == FAIL)
10008a7d6542SBram Moolenaar 			    goto failed;
10018a7d6542SBram Moolenaar 			copy_tv(&di->di_tv, STACK_TV_BOT(0));
10028a7d6542SBram Moolenaar 			++ectx.ec_stack.ga_len;
10038a7d6542SBram Moolenaar 		    }
10048a7d6542SBram Moolenaar 		}
10058a7d6542SBram Moolenaar 		break;
10068a7d6542SBram Moolenaar 
1007d3aac291SBram Moolenaar 	    // load g:/b:/w:/t: variable
10088a7d6542SBram Moolenaar 	    case ISN_LOADG:
1009d3aac291SBram Moolenaar 	    case ISN_LOADB:
1010d3aac291SBram Moolenaar 	    case ISN_LOADW:
1011d3aac291SBram Moolenaar 	    case ISN_LOADT:
10128a7d6542SBram Moolenaar 		{
1013d3aac291SBram Moolenaar 		    dictitem_T *di = NULL;
1014d3aac291SBram Moolenaar 		    hashtab_T *ht = NULL;
1015d3aac291SBram Moolenaar 		    char namespace;
1016d3aac291SBram Moolenaar 		    switch (iptr->isn_type)
1017d3aac291SBram Moolenaar 		    {
1018d3aac291SBram Moolenaar 			case ISN_LOADG:
1019d3aac291SBram Moolenaar 			    ht = get_globvar_ht();
1020d3aac291SBram Moolenaar 			    namespace = 'g';
1021d3aac291SBram Moolenaar 			    break;
1022d3aac291SBram Moolenaar 			case ISN_LOADB:
1023d3aac291SBram Moolenaar 			    ht = &curbuf->b_vars->dv_hashtab;
1024d3aac291SBram Moolenaar 			    namespace = 'b';
1025d3aac291SBram Moolenaar 			    break;
1026d3aac291SBram Moolenaar 			case ISN_LOADW:
1027d3aac291SBram Moolenaar 			    ht = &curwin->w_vars->dv_hashtab;
1028d3aac291SBram Moolenaar 			    namespace = 'w';
1029d3aac291SBram Moolenaar 			    break;
1030d3aac291SBram Moolenaar 			case ISN_LOADT:
1031d3aac291SBram Moolenaar 			    ht = &curtab->tp_vars->dv_hashtab;
1032d3aac291SBram Moolenaar 			    namespace = 't';
1033d3aac291SBram Moolenaar 			    break;
1034d3aac291SBram Moolenaar 			default:  // Cannot reach here
1035d3aac291SBram Moolenaar 			    goto failed;
1036d3aac291SBram Moolenaar 		    }
1037d3aac291SBram Moolenaar 		    di = find_var_in_ht(ht, 0, iptr->isn_arg.string, TRUE);
10380bbf722aSBram Moolenaar 
10398a7d6542SBram Moolenaar 		    if (di == NULL)
10408a7d6542SBram Moolenaar 		    {
1041d3aac291SBram Moolenaar 			semsg(_("E121: Undefined variable: %c:%s"),
1042d3aac291SBram Moolenaar 					     namespace, iptr->isn_arg.string);
10438a7d6542SBram Moolenaar 			goto failed;
10448a7d6542SBram Moolenaar 		    }
10458a7d6542SBram Moolenaar 		    else
10468a7d6542SBram Moolenaar 		    {
10478a7d6542SBram Moolenaar 			if (ga_grow(&ectx.ec_stack, 1) == FAIL)
10488a7d6542SBram Moolenaar 			    goto failed;
10498a7d6542SBram Moolenaar 			copy_tv(&di->di_tv, STACK_TV_BOT(0));
10508a7d6542SBram Moolenaar 			++ectx.ec_stack.ga_len;
10518a7d6542SBram Moolenaar 		    }
10528a7d6542SBram Moolenaar 		}
10538a7d6542SBram Moolenaar 		break;
10548a7d6542SBram Moolenaar 
10558a7d6542SBram Moolenaar 	    // load &option
10568a7d6542SBram Moolenaar 	    case ISN_LOADOPT:
10578a7d6542SBram Moolenaar 		{
10588a7d6542SBram Moolenaar 		    typval_T	optval;
10598a7d6542SBram Moolenaar 		    char_u	*name = iptr->isn_arg.string;
10608a7d6542SBram Moolenaar 
1061a8c17704SBram Moolenaar 		    // This is not expected to fail, name is checked during
1062a8c17704SBram Moolenaar 		    // compilation: don't set SOURCING_LNUM.
10638a7d6542SBram Moolenaar 		    if (ga_grow(&ectx.ec_stack, 1) == FAIL)
10648a7d6542SBram Moolenaar 			goto failed;
106558ceca5cSBram Moolenaar 		    if (get_option_tv(&name, &optval, TRUE) == FAIL)
106658ceca5cSBram Moolenaar 			goto failed;
10678a7d6542SBram Moolenaar 		    *STACK_TV_BOT(0) = optval;
10688a7d6542SBram Moolenaar 		    ++ectx.ec_stack.ga_len;
10698a7d6542SBram Moolenaar 		}
10708a7d6542SBram Moolenaar 		break;
10718a7d6542SBram Moolenaar 
10728a7d6542SBram Moolenaar 	    // load $ENV
10738a7d6542SBram Moolenaar 	    case ISN_LOADENV:
10748a7d6542SBram Moolenaar 		{
10758a7d6542SBram Moolenaar 		    typval_T	optval;
10768a7d6542SBram Moolenaar 		    char_u	*name = iptr->isn_arg.string;
10778a7d6542SBram Moolenaar 
10788a7d6542SBram Moolenaar 		    if (ga_grow(&ectx.ec_stack, 1) == FAIL)
10798a7d6542SBram Moolenaar 			goto failed;
10800bbf722aSBram Moolenaar 		    // name is always valid, checked when compiling
10810bbf722aSBram Moolenaar 		    (void)get_env_tv(&name, &optval, TRUE);
10828a7d6542SBram Moolenaar 		    *STACK_TV_BOT(0) = optval;
10838a7d6542SBram Moolenaar 		    ++ectx.ec_stack.ga_len;
10848a7d6542SBram Moolenaar 		}
10858a7d6542SBram Moolenaar 		break;
10868a7d6542SBram Moolenaar 
10878a7d6542SBram Moolenaar 	    // load @register
10888a7d6542SBram Moolenaar 	    case ISN_LOADREG:
10898a7d6542SBram Moolenaar 		if (ga_grow(&ectx.ec_stack, 1) == FAIL)
10908a7d6542SBram Moolenaar 		    goto failed;
10918a7d6542SBram Moolenaar 		tv = STACK_TV_BOT(0);
10928a7d6542SBram Moolenaar 		tv->v_type = VAR_STRING;
10938a7d6542SBram Moolenaar 		tv->vval.v_string = get_reg_contents(
10948a7d6542SBram Moolenaar 					  iptr->isn_arg.number, GREG_EXPR_SRC);
10958a7d6542SBram Moolenaar 		++ectx.ec_stack.ga_len;
10968a7d6542SBram Moolenaar 		break;
10978a7d6542SBram Moolenaar 
10988a7d6542SBram Moolenaar 	    // store local variable
10998a7d6542SBram Moolenaar 	    case ISN_STORE:
11008a7d6542SBram Moolenaar 		--ectx.ec_stack.ga_len;
11018a7d6542SBram Moolenaar 		tv = STACK_TV_VAR(iptr->isn_arg.number);
11028a7d6542SBram Moolenaar 		clear_tv(tv);
11038a7d6542SBram Moolenaar 		*tv = *STACK_TV_BOT(0);
11048a7d6542SBram Moolenaar 		break;
11058a7d6542SBram Moolenaar 
1106b68b346eSBram Moolenaar 	    // store variable or argument in outer scope
1107b68b346eSBram Moolenaar 	    case ISN_STOREOUTER:
1108b68b346eSBram Moolenaar 		--ectx.ec_stack.ga_len;
1109b68b346eSBram Moolenaar 		tv = STACK_OUT_TV_VAR(iptr->isn_arg.number);
1110b68b346eSBram Moolenaar 		clear_tv(tv);
1111b68b346eSBram Moolenaar 		*tv = *STACK_TV_BOT(0);
1112b68b346eSBram Moolenaar 		break;
1113b68b346eSBram Moolenaar 
1114b283a8a6SBram Moolenaar 	    // store s: variable in old script
1115b283a8a6SBram Moolenaar 	    case ISN_STORES:
1116b283a8a6SBram Moolenaar 		{
1117b283a8a6SBram Moolenaar 		    hashtab_T	*ht = &SCRIPT_VARS(
1118b283a8a6SBram Moolenaar 					       iptr->isn_arg.loadstore.ls_sid);
1119b283a8a6SBram Moolenaar 		    char_u	*name = iptr->isn_arg.loadstore.ls_name;
11200bbf722aSBram Moolenaar 		    dictitem_T	*di = find_var_in_ht(ht, 0, name + 2, TRUE);
1121b283a8a6SBram Moolenaar 
1122b283a8a6SBram Moolenaar 		    --ectx.ec_stack.ga_len;
11230bbf722aSBram Moolenaar 		    if (di == NULL)
11245deeb3f1SBram Moolenaar 			store_var(name, STACK_TV_BOT(0));
11250bbf722aSBram Moolenaar 		    else
11260bbf722aSBram Moolenaar 		    {
1127b283a8a6SBram Moolenaar 			clear_tv(&di->di_tv);
1128b283a8a6SBram Moolenaar 			di->di_tv = *STACK_TV_BOT(0);
1129b283a8a6SBram Moolenaar 		    }
11300bbf722aSBram Moolenaar 		}
1131b283a8a6SBram Moolenaar 		break;
1132b283a8a6SBram Moolenaar 
1133b283a8a6SBram Moolenaar 	    // store script-local variable in Vim9 script
11348a7d6542SBram Moolenaar 	    case ISN_STORESCRIPT:
11358a7d6542SBram Moolenaar 		{
113621b9e977SBram Moolenaar 		    scriptitem_T *si = SCRIPT_ITEM(
11378a7d6542SBram Moolenaar 					      iptr->isn_arg.script.script_sid);
11388a7d6542SBram Moolenaar 		    svar_T	 *sv = ((svar_T *)si->sn_var_vals.ga_data)
11398a7d6542SBram Moolenaar 					     + iptr->isn_arg.script.script_idx;
11408a7d6542SBram Moolenaar 
11418a7d6542SBram Moolenaar 		    --ectx.ec_stack.ga_len;
11428a7d6542SBram Moolenaar 		    clear_tv(sv->sv_tv);
11438a7d6542SBram Moolenaar 		    *sv->sv_tv = *STACK_TV_BOT(0);
11448a7d6542SBram Moolenaar 		}
11458a7d6542SBram Moolenaar 		break;
11468a7d6542SBram Moolenaar 
11478a7d6542SBram Moolenaar 	    // store option
11488a7d6542SBram Moolenaar 	    case ISN_STOREOPT:
11498a7d6542SBram Moolenaar 		{
11508a7d6542SBram Moolenaar 		    long	n = 0;
11518a7d6542SBram Moolenaar 		    char_u	*s = NULL;
11528a7d6542SBram Moolenaar 		    char	*msg;
11538a7d6542SBram Moolenaar 
11548a7d6542SBram Moolenaar 		    --ectx.ec_stack.ga_len;
11558a7d6542SBram Moolenaar 		    tv = STACK_TV_BOT(0);
11568a7d6542SBram Moolenaar 		    if (tv->v_type == VAR_STRING)
115797a2af39SBram Moolenaar 		    {
11588a7d6542SBram Moolenaar 			s = tv->vval.v_string;
115997a2af39SBram Moolenaar 			if (s == NULL)
116097a2af39SBram Moolenaar 			    s = (char_u *)"";
116197a2af39SBram Moolenaar 		    }
11628a7d6542SBram Moolenaar 		    else if (tv->v_type == VAR_NUMBER)
11638a7d6542SBram Moolenaar 			n = tv->vval.v_number;
11648a7d6542SBram Moolenaar 		    else
11658a7d6542SBram Moolenaar 		    {
11668a7d6542SBram Moolenaar 			emsg(_("E1051: Expected string or number"));
11678a7d6542SBram Moolenaar 			goto failed;
11688a7d6542SBram Moolenaar 		    }
11698a7d6542SBram Moolenaar 		    msg = set_option_value(iptr->isn_arg.storeopt.so_name,
11708a7d6542SBram Moolenaar 					n, s, iptr->isn_arg.storeopt.so_flags);
11718a7d6542SBram Moolenaar 		    if (msg != NULL)
11728a7d6542SBram Moolenaar 		    {
11738a7d6542SBram Moolenaar 			emsg(_(msg));
11748a7d6542SBram Moolenaar 			goto failed;
11758a7d6542SBram Moolenaar 		    }
11768a7d6542SBram Moolenaar 		    clear_tv(tv);
11778a7d6542SBram Moolenaar 		}
11788a7d6542SBram Moolenaar 		break;
11798a7d6542SBram Moolenaar 
1180b283a8a6SBram Moolenaar 	    // store $ENV
1181b283a8a6SBram Moolenaar 	    case ISN_STOREENV:
1182b283a8a6SBram Moolenaar 		--ectx.ec_stack.ga_len;
118320431c9dSBram Moolenaar 		tv = STACK_TV_BOT(0);
118420431c9dSBram Moolenaar 		vim_setenv_ext(iptr->isn_arg.string, tv_get_string(tv));
118520431c9dSBram Moolenaar 		clear_tv(tv);
1186b283a8a6SBram Moolenaar 		break;
1187b283a8a6SBram Moolenaar 
1188b283a8a6SBram Moolenaar 	    // store @r
1189b283a8a6SBram Moolenaar 	    case ISN_STOREREG:
1190b283a8a6SBram Moolenaar 		{
1191b283a8a6SBram Moolenaar 		    int	reg = iptr->isn_arg.number;
1192b283a8a6SBram Moolenaar 
1193b283a8a6SBram Moolenaar 		    --ectx.ec_stack.ga_len;
1194401d9ffbSBram Moolenaar 		    tv = STACK_TV_BOT(0);
1195b283a8a6SBram Moolenaar 		    write_reg_contents(reg == '@' ? '"' : reg,
1196401d9ffbSBram Moolenaar 						 tv_get_string(tv), -1, FALSE);
1197401d9ffbSBram Moolenaar 		    clear_tv(tv);
1198b283a8a6SBram Moolenaar 		}
1199b283a8a6SBram Moolenaar 		break;
1200b283a8a6SBram Moolenaar 
1201b283a8a6SBram Moolenaar 	    // store v: variable
1202b283a8a6SBram Moolenaar 	    case ISN_STOREV:
1203b283a8a6SBram Moolenaar 		--ectx.ec_stack.ga_len;
1204b283a8a6SBram Moolenaar 		if (set_vim_var_tv(iptr->isn_arg.number, STACK_TV_BOT(0))
1205b283a8a6SBram Moolenaar 								       == FAIL)
1206b283a8a6SBram Moolenaar 		    goto failed;
1207b283a8a6SBram Moolenaar 		break;
1208b283a8a6SBram Moolenaar 
1209d3aac291SBram Moolenaar 	    // store g:/b:/w:/t: variable
12108a7d6542SBram Moolenaar 	    case ISN_STOREG:
1211d3aac291SBram Moolenaar 	    case ISN_STOREB:
1212d3aac291SBram Moolenaar 	    case ISN_STOREW:
1213d3aac291SBram Moolenaar 	    case ISN_STORET:
12148a7d6542SBram Moolenaar 		{
12158a7d6542SBram Moolenaar 		    dictitem_T *di;
1216d3aac291SBram Moolenaar 		    hashtab_T *ht;
1217d3aac291SBram Moolenaar 		    switch (iptr->isn_type)
1218d3aac291SBram Moolenaar 		    {
1219d3aac291SBram Moolenaar 			case ISN_STOREG:
1220d3aac291SBram Moolenaar 			    ht = get_globvar_ht();
1221d3aac291SBram Moolenaar 			    break;
1222d3aac291SBram Moolenaar 			case ISN_STOREB:
1223d3aac291SBram Moolenaar 			    ht = &curbuf->b_vars->dv_hashtab;
1224d3aac291SBram Moolenaar 			    break;
1225d3aac291SBram Moolenaar 			case ISN_STOREW:
1226d3aac291SBram Moolenaar 			    ht = &curwin->w_vars->dv_hashtab;
1227d3aac291SBram Moolenaar 			    break;
1228d3aac291SBram Moolenaar 			case ISN_STORET:
1229d3aac291SBram Moolenaar 			    ht = &curtab->tp_vars->dv_hashtab;
1230d3aac291SBram Moolenaar 			    break;
1231d3aac291SBram Moolenaar 			default:  // Cannot reach here
1232d3aac291SBram Moolenaar 			    goto failed;
1233d3aac291SBram Moolenaar 		    }
12348a7d6542SBram Moolenaar 
12358a7d6542SBram Moolenaar 		    --ectx.ec_stack.ga_len;
1236bf67ea1aSBram Moolenaar 		    di = find_var_in_ht(ht, 0, iptr->isn_arg.string + 2, TRUE);
12378a7d6542SBram Moolenaar 		    if (di == NULL)
12380bbf722aSBram Moolenaar 			store_var(iptr->isn_arg.string, STACK_TV_BOT(0));
12398a7d6542SBram Moolenaar 		    else
12408a7d6542SBram Moolenaar 		    {
12418a7d6542SBram Moolenaar 			clear_tv(&di->di_tv);
12428a7d6542SBram Moolenaar 			di->di_tv = *STACK_TV_BOT(0);
12438a7d6542SBram Moolenaar 		    }
12448a7d6542SBram Moolenaar 		}
12458a7d6542SBram Moolenaar 		break;
12468a7d6542SBram Moolenaar 
12478a7d6542SBram Moolenaar 	    // store number in local variable
12488a7d6542SBram Moolenaar 	    case ISN_STORENR:
1249a471eeaeSBram Moolenaar 		tv = STACK_TV_VAR(iptr->isn_arg.storenr.stnr_idx);
12508a7d6542SBram Moolenaar 		clear_tv(tv);
12518a7d6542SBram Moolenaar 		tv->v_type = VAR_NUMBER;
1252a471eeaeSBram Moolenaar 		tv->vval.v_number = iptr->isn_arg.storenr.stnr_val;
12538a7d6542SBram Moolenaar 		break;
12548a7d6542SBram Moolenaar 
12558a7d6542SBram Moolenaar 	    // push constant
12568a7d6542SBram Moolenaar 	    case ISN_PUSHNR:
12578a7d6542SBram Moolenaar 	    case ISN_PUSHBOOL:
12588a7d6542SBram Moolenaar 	    case ISN_PUSHSPEC:
12598a7d6542SBram Moolenaar 	    case ISN_PUSHF:
12608a7d6542SBram Moolenaar 	    case ISN_PUSHS:
12618a7d6542SBram Moolenaar 	    case ISN_PUSHBLOB:
126242a480bfSBram Moolenaar 	    case ISN_PUSHFUNC:
126342a480bfSBram Moolenaar 	    case ISN_PUSHCHANNEL:
126442a480bfSBram Moolenaar 	    case ISN_PUSHJOB:
12658a7d6542SBram Moolenaar 		if (ga_grow(&ectx.ec_stack, 1) == FAIL)
12668a7d6542SBram Moolenaar 		    goto failed;
12678a7d6542SBram Moolenaar 		tv = STACK_TV_BOT(0);
12688a7d6542SBram Moolenaar 		++ectx.ec_stack.ga_len;
12698a7d6542SBram Moolenaar 		switch (iptr->isn_type)
12708a7d6542SBram Moolenaar 		{
12718a7d6542SBram Moolenaar 		    case ISN_PUSHNR:
12728a7d6542SBram Moolenaar 			tv->v_type = VAR_NUMBER;
12738a7d6542SBram Moolenaar 			tv->vval.v_number = iptr->isn_arg.number;
12748a7d6542SBram Moolenaar 			break;
12758a7d6542SBram Moolenaar 		    case ISN_PUSHBOOL:
12768a7d6542SBram Moolenaar 			tv->v_type = VAR_BOOL;
12778a7d6542SBram Moolenaar 			tv->vval.v_number = iptr->isn_arg.number;
12788a7d6542SBram Moolenaar 			break;
12798a7d6542SBram Moolenaar 		    case ISN_PUSHSPEC:
12808a7d6542SBram Moolenaar 			tv->v_type = VAR_SPECIAL;
12818a7d6542SBram Moolenaar 			tv->vval.v_number = iptr->isn_arg.number;
12828a7d6542SBram Moolenaar 			break;
12838a7d6542SBram Moolenaar #ifdef FEAT_FLOAT
12848a7d6542SBram Moolenaar 		    case ISN_PUSHF:
12858a7d6542SBram Moolenaar 			tv->v_type = VAR_FLOAT;
12868a7d6542SBram Moolenaar 			tv->vval.v_float = iptr->isn_arg.fnumber;
12878a7d6542SBram Moolenaar 			break;
12888a7d6542SBram Moolenaar #endif
12898a7d6542SBram Moolenaar 		    case ISN_PUSHBLOB:
12908a7d6542SBram Moolenaar 			blob_copy(iptr->isn_arg.blob, tv);
12918a7d6542SBram Moolenaar 			break;
129242a480bfSBram Moolenaar 		    case ISN_PUSHFUNC:
129342a480bfSBram Moolenaar 			tv->v_type = VAR_FUNC;
1294087d2e15SBram Moolenaar 			if (iptr->isn_arg.string == NULL)
1295087d2e15SBram Moolenaar 			    tv->vval.v_string = NULL;
1296087d2e15SBram Moolenaar 			else
1297087d2e15SBram Moolenaar 			    tv->vval.v_string =
1298087d2e15SBram Moolenaar 					     vim_strsave(iptr->isn_arg.string);
129942a480bfSBram Moolenaar 			break;
130042a480bfSBram Moolenaar 		    case ISN_PUSHCHANNEL:
130142a480bfSBram Moolenaar #ifdef FEAT_JOB_CHANNEL
130242a480bfSBram Moolenaar 			tv->v_type = VAR_CHANNEL;
130342a480bfSBram Moolenaar 			tv->vval.v_channel = iptr->isn_arg.channel;
130442a480bfSBram Moolenaar 			if (tv->vval.v_channel != NULL)
130542a480bfSBram Moolenaar 			    ++tv->vval.v_channel->ch_refcount;
130642a480bfSBram Moolenaar #endif
130742a480bfSBram Moolenaar 			break;
130842a480bfSBram Moolenaar 		    case ISN_PUSHJOB:
130942a480bfSBram Moolenaar #ifdef FEAT_JOB_CHANNEL
131042a480bfSBram Moolenaar 			tv->v_type = VAR_JOB;
131142a480bfSBram Moolenaar 			tv->vval.v_job = iptr->isn_arg.job;
131242a480bfSBram Moolenaar 			if (tv->vval.v_job != NULL)
131342a480bfSBram Moolenaar 			    ++tv->vval.v_job->jv_refcount;
131442a480bfSBram Moolenaar #endif
131542a480bfSBram Moolenaar 			break;
13168a7d6542SBram Moolenaar 		    default:
13178a7d6542SBram Moolenaar 			tv->v_type = VAR_STRING;
1318e69f6d04SBram Moolenaar 			tv->vval.v_string = vim_strsave(
1319e69f6d04SBram Moolenaar 				iptr->isn_arg.string == NULL
1320e69f6d04SBram Moolenaar 					? (char_u *)"" : iptr->isn_arg.string);
13218a7d6542SBram Moolenaar 		}
13228a7d6542SBram Moolenaar 		break;
13238a7d6542SBram Moolenaar 
1324d72c1bf0SBram Moolenaar 	    case ISN_UNLET:
1325d72c1bf0SBram Moolenaar 		if (do_unlet(iptr->isn_arg.unlet.ul_name,
1326d72c1bf0SBram Moolenaar 				       iptr->isn_arg.unlet.ul_forceit) == FAIL)
1327d72c1bf0SBram Moolenaar 		    goto failed;
1328d72c1bf0SBram Moolenaar 		break;
13297bdaea6eSBram Moolenaar 	    case ISN_UNLETENV:
13307bdaea6eSBram Moolenaar 		vim_unsetenv(iptr->isn_arg.unlet.ul_name);
13317bdaea6eSBram Moolenaar 		break;
1332d72c1bf0SBram Moolenaar 
13338a7d6542SBram Moolenaar 	    // create a list from items on the stack; uses a single allocation
13348a7d6542SBram Moolenaar 	    // for the list header and the items
13358a7d6542SBram Moolenaar 	    case ISN_NEWLIST:
1336fe270817SBram Moolenaar 		if (exe_newlist(iptr->isn_arg.number, &ectx) == FAIL)
13378a7d6542SBram Moolenaar 		    goto failed;
13388a7d6542SBram Moolenaar 		break;
13398a7d6542SBram Moolenaar 
13408a7d6542SBram Moolenaar 	    // create a dict from items on the stack
13418a7d6542SBram Moolenaar 	    case ISN_NEWDICT:
13428a7d6542SBram Moolenaar 		{
13438a7d6542SBram Moolenaar 		    int	    count = iptr->isn_arg.number;
13448a7d6542SBram Moolenaar 		    dict_T  *dict = dict_alloc();
13458a7d6542SBram Moolenaar 		    dictitem_T *item;
13468a7d6542SBram Moolenaar 
13478a7d6542SBram Moolenaar 		    if (dict == NULL)
13488a7d6542SBram Moolenaar 			goto failed;
13498a7d6542SBram Moolenaar 		    for (idx = 0; idx < count; ++idx)
13508a7d6542SBram Moolenaar 		    {
13518a7d6542SBram Moolenaar 			// check key type is VAR_STRING
13528a7d6542SBram Moolenaar 			tv = STACK_TV_BOT(2 * (idx - count));
13538a7d6542SBram Moolenaar 			item = dictitem_alloc(tv->vval.v_string);
13548a7d6542SBram Moolenaar 			clear_tv(tv);
13558a7d6542SBram Moolenaar 			if (item == NULL)
13568a7d6542SBram Moolenaar 			    goto failed;
13578a7d6542SBram Moolenaar 			item->di_tv = *STACK_TV_BOT(2 * (idx - count) + 1);
13588a7d6542SBram Moolenaar 			item->di_tv.v_lock = 0;
13598a7d6542SBram Moolenaar 			if (dict_add(dict, item) == FAIL)
13608a7d6542SBram Moolenaar 			    goto failed;
13618a7d6542SBram Moolenaar 		    }
13628a7d6542SBram Moolenaar 
13638a7d6542SBram Moolenaar 		    if (count > 0)
13648a7d6542SBram Moolenaar 			ectx.ec_stack.ga_len -= 2 * count - 1;
13658a7d6542SBram Moolenaar 		    else if (ga_grow(&ectx.ec_stack, 1) == FAIL)
13668a7d6542SBram Moolenaar 			goto failed;
13678a7d6542SBram Moolenaar 		    else
13688a7d6542SBram Moolenaar 			++ectx.ec_stack.ga_len;
13698a7d6542SBram Moolenaar 		    tv = STACK_TV_BOT(-1);
13708a7d6542SBram Moolenaar 		    tv->v_type = VAR_DICT;
13718a7d6542SBram Moolenaar 		    tv->vval.v_dict = dict;
13728a7d6542SBram Moolenaar 		    ++dict->dv_refcount;
13738a7d6542SBram Moolenaar 		}
13748a7d6542SBram Moolenaar 		break;
13758a7d6542SBram Moolenaar 
13768a7d6542SBram Moolenaar 	    // call a :def function
13778a7d6542SBram Moolenaar 	    case ISN_DCALL:
13788a7d6542SBram Moolenaar 		if (call_dfunc(iptr->isn_arg.dfunc.cdf_idx,
13798a7d6542SBram Moolenaar 			      iptr->isn_arg.dfunc.cdf_argcount,
13808a7d6542SBram Moolenaar 			      &ectx) == FAIL)
13818a7d6542SBram Moolenaar 		    goto failed;
13828a7d6542SBram Moolenaar 		break;
13838a7d6542SBram Moolenaar 
13848a7d6542SBram Moolenaar 	    // call a builtin function
13858a7d6542SBram Moolenaar 	    case ISN_BCALL:
13868a7d6542SBram Moolenaar 		SOURCING_LNUM = iptr->isn_lnum;
13878a7d6542SBram Moolenaar 		if (call_bfunc(iptr->isn_arg.bfunc.cbf_idx,
13888a7d6542SBram Moolenaar 			      iptr->isn_arg.bfunc.cbf_argcount,
13898a7d6542SBram Moolenaar 			      &ectx) == FAIL)
13908a7d6542SBram Moolenaar 		    goto failed;
13918a7d6542SBram Moolenaar 		break;
13928a7d6542SBram Moolenaar 
13938a7d6542SBram Moolenaar 	    // call a funcref or partial
13948a7d6542SBram Moolenaar 	    case ISN_PCALL:
13958a7d6542SBram Moolenaar 		{
13968a7d6542SBram Moolenaar 		    cpfunc_T	*pfunc = &iptr->isn_arg.pfunc;
13978a7d6542SBram Moolenaar 		    int		r;
13988a7d6542SBram Moolenaar 		    typval_T	partial;
13998a7d6542SBram Moolenaar 
14008a7d6542SBram Moolenaar 		    SOURCING_LNUM = iptr->isn_lnum;
14018a7d6542SBram Moolenaar 		    if (pfunc->cpf_top)
14028a7d6542SBram Moolenaar 		    {
14038a7d6542SBram Moolenaar 			// funcref is above the arguments
14048a7d6542SBram Moolenaar 			tv = STACK_TV_BOT(-pfunc->cpf_argcount - 1);
14058a7d6542SBram Moolenaar 		    }
14068a7d6542SBram Moolenaar 		    else
14078a7d6542SBram Moolenaar 		    {
14088a7d6542SBram Moolenaar 			// Get the funcref from the stack.
14098a7d6542SBram Moolenaar 			--ectx.ec_stack.ga_len;
14108a7d6542SBram Moolenaar 			partial = *STACK_TV_BOT(0);
14118a7d6542SBram Moolenaar 			tv = &partial;
14128a7d6542SBram Moolenaar 		    }
14138a7d6542SBram Moolenaar 		    r = call_partial(tv, pfunc->cpf_argcount, &ectx);
14148a7d6542SBram Moolenaar 		    if (tv == &partial)
14158a7d6542SBram Moolenaar 			clear_tv(&partial);
14168a7d6542SBram Moolenaar 		    if (r == FAIL)
14178a7d6542SBram Moolenaar 			goto failed;
1418bd5da371SBram Moolenaar 		}
1419bd5da371SBram Moolenaar 		break;
14208a7d6542SBram Moolenaar 
1421bd5da371SBram Moolenaar 	    case ISN_PCALL_END:
1422bd5da371SBram Moolenaar 		// PCALL finished, arguments have been consumed and replaced by
1423bd5da371SBram Moolenaar 		// the return value.  Now clear the funcref from the stack,
1424bd5da371SBram Moolenaar 		// and move the return value in its place.
14258a7d6542SBram Moolenaar 		--ectx.ec_stack.ga_len;
1426bd5da371SBram Moolenaar 		clear_tv(STACK_TV_BOT(-1));
14278a7d6542SBram Moolenaar 		*STACK_TV_BOT(-1) = *STACK_TV_BOT(0);
14288a7d6542SBram Moolenaar 		break;
14298a7d6542SBram Moolenaar 
14308a7d6542SBram Moolenaar 	    // call a user defined function or funcref/partial
14318a7d6542SBram Moolenaar 	    case ISN_UCALL:
14328a7d6542SBram Moolenaar 		{
14338a7d6542SBram Moolenaar 		    cufunc_T	*cufunc = &iptr->isn_arg.ufunc;
14348a7d6542SBram Moolenaar 
14358a7d6542SBram Moolenaar 		    SOURCING_LNUM = iptr->isn_lnum;
14368a7d6542SBram Moolenaar 		    if (call_eval_func(cufunc->cuf_name,
14377eeefd4aSBram Moolenaar 				    cufunc->cuf_argcount, &ectx, iptr) == FAIL)
14388a7d6542SBram Moolenaar 			goto failed;
14398a7d6542SBram Moolenaar 		}
14408a7d6542SBram Moolenaar 		break;
14418a7d6542SBram Moolenaar 
14428a7d6542SBram Moolenaar 	    // return from a :def function call
14438a7d6542SBram Moolenaar 	    case ISN_RETURN:
14448a7d6542SBram Moolenaar 		{
14458cbd6dfcSBram Moolenaar 		    garray_T	*trystack = &ectx.ec_trystack;
144620431c9dSBram Moolenaar 		    trycmd_T    *trycmd = NULL;
14478cbd6dfcSBram Moolenaar 
14488cbd6dfcSBram Moolenaar 		    if (trystack->ga_len > 0)
14498cbd6dfcSBram Moolenaar 			trycmd = ((trycmd_T *)trystack->ga_data)
14508cbd6dfcSBram Moolenaar 							+ trystack->ga_len - 1;
1451bf67ea1aSBram Moolenaar 		    if (trycmd != NULL
1452bf67ea1aSBram Moolenaar 				  && trycmd->tcd_frame_idx == ectx.ec_frame_idx
14538a7d6542SBram Moolenaar 			    && trycmd->tcd_finally_idx != 0)
14548a7d6542SBram Moolenaar 		    {
14558a7d6542SBram Moolenaar 			// jump to ":finally"
14568a7d6542SBram Moolenaar 			ectx.ec_iidx = trycmd->tcd_finally_idx;
14578a7d6542SBram Moolenaar 			trycmd->tcd_return = TRUE;
14588a7d6542SBram Moolenaar 		    }
14598a7d6542SBram Moolenaar 		    else
14608a7d6542SBram Moolenaar 		    {
14618a7d6542SBram Moolenaar 			// Restore previous function. If the frame pointer
14628a7d6542SBram Moolenaar 			// is zero then there is none and we are done.
1463bf67ea1aSBram Moolenaar 			if (ectx.ec_frame_idx == initial_frame_idx)
1464bf67ea1aSBram Moolenaar 			{
1465bf67ea1aSBram Moolenaar 			    if (handle_closure_in_use(&ectx, FALSE) == FAIL)
1466bf67ea1aSBram Moolenaar 				goto failed;
14678a7d6542SBram Moolenaar 			    goto done;
1468bf67ea1aSBram Moolenaar 			}
14698a7d6542SBram Moolenaar 
1470bf67ea1aSBram Moolenaar 			if (func_return(&ectx) == FAIL)
1471bf67ea1aSBram Moolenaar 			    goto failed;
14728a7d6542SBram Moolenaar 		    }
14738a7d6542SBram Moolenaar 		}
14748a7d6542SBram Moolenaar 		break;
14758a7d6542SBram Moolenaar 
14768a7d6542SBram Moolenaar 	    // push a function reference to a compiled function
14778a7d6542SBram Moolenaar 	    case ISN_FUNCREF:
14788a7d6542SBram Moolenaar 		{
14798a7d6542SBram Moolenaar 		    partial_T   *pt = NULL;
1480bf67ea1aSBram Moolenaar 		    dfunc_T	*pt_dfunc;
14818a7d6542SBram Moolenaar 
14828a7d6542SBram Moolenaar 		    pt = ALLOC_CLEAR_ONE(partial_T);
14838a7d6542SBram Moolenaar 		    if (pt == NULL)
14848a7d6542SBram Moolenaar 			goto failed;
1485bf67ea1aSBram Moolenaar 		    if (ga_grow(&ectx.ec_stack, 1) == FAIL)
1486c8cd2b34SBram Moolenaar 		    {
1487bf67ea1aSBram Moolenaar 			vim_free(pt);
1488bf67ea1aSBram Moolenaar 			goto failed;
1489bf67ea1aSBram Moolenaar 		    }
1490bf67ea1aSBram Moolenaar 		    pt_dfunc = ((dfunc_T *)def_functions.ga_data)
1491bf67ea1aSBram Moolenaar 					       + iptr->isn_arg.funcref.fr_func;
1492bf67ea1aSBram Moolenaar 		    pt->pt_func = pt_dfunc->df_ufunc;
1493bf67ea1aSBram Moolenaar 		    pt->pt_refcount = 1;
1494bf67ea1aSBram Moolenaar 		    ++pt_dfunc->df_ufunc->uf_refcount;
1495bf67ea1aSBram Moolenaar 
1496bf67ea1aSBram Moolenaar 		    if (pt_dfunc->df_ufunc->uf_flags & FC_CLOSURE)
1497bf67ea1aSBram Moolenaar 		    {
1498bf67ea1aSBram Moolenaar 			dfunc_T	*dfunc = ((dfunc_T *)def_functions.ga_data)
1499bf67ea1aSBram Moolenaar 							   + ectx.ec_dfunc_idx;
1500bf67ea1aSBram Moolenaar 
1501bf67ea1aSBram Moolenaar 			// The closure needs to find arguments and local
1502bf67ea1aSBram Moolenaar 			// variables in the current stack.
1503f7779c63SBram Moolenaar 			pt->pt_ectx_stack = &ectx.ec_stack;
1504f7779c63SBram Moolenaar 			pt->pt_ectx_frame = ectx.ec_frame_idx;
1505bf67ea1aSBram Moolenaar 
1506bf67ea1aSBram Moolenaar 			// If this function returns and the closure is still
1507bf67ea1aSBram Moolenaar 			// used, we need to make a copy of the context
1508bf67ea1aSBram Moolenaar 			// (arguments and local variables). Store a reference
1509bf67ea1aSBram Moolenaar 			// to the partial so we can handle that.
1510bf67ea1aSBram Moolenaar 			++pt->pt_refcount;
1511bf67ea1aSBram Moolenaar 			tv = STACK_TV_VAR(dfunc->df_varcount
1512bf67ea1aSBram Moolenaar 					   + iptr->isn_arg.funcref.fr_var_idx);
1513bf67ea1aSBram Moolenaar 			if (tv->v_type == VAR_PARTIAL)
1514bf67ea1aSBram Moolenaar 			{
1515bf67ea1aSBram Moolenaar 			    // TODO: use a garray_T on ectx.
1516bf67ea1aSBram Moolenaar 			    emsg("Multiple closures not supported yet");
1517bf67ea1aSBram Moolenaar 			    goto failed;
1518bf67ea1aSBram Moolenaar 			}
1519bf67ea1aSBram Moolenaar 			tv->v_type = VAR_PARTIAL;
1520bf67ea1aSBram Moolenaar 			tv->vval.v_partial = pt;
1521c8cd2b34SBram Moolenaar 		    }
1522c8cd2b34SBram Moolenaar 
15238a7d6542SBram Moolenaar 		    tv = STACK_TV_BOT(0);
15248a7d6542SBram Moolenaar 		    ++ectx.ec_stack.ga_len;
15258a7d6542SBram Moolenaar 		    tv->vval.v_partial = pt;
15268a7d6542SBram Moolenaar 		    tv->v_type = VAR_PARTIAL;
15278a7d6542SBram Moolenaar 		}
15288a7d6542SBram Moolenaar 		break;
15298a7d6542SBram Moolenaar 
15308a7d6542SBram Moolenaar 	    // jump if a condition is met
15318a7d6542SBram Moolenaar 	    case ISN_JUMP:
15328a7d6542SBram Moolenaar 		{
15338a7d6542SBram Moolenaar 		    jumpwhen_T	when = iptr->isn_arg.jump.jump_when;
15348a7d6542SBram Moolenaar 		    int		jump = TRUE;
15358a7d6542SBram Moolenaar 
15368a7d6542SBram Moolenaar 		    if (when != JUMP_ALWAYS)
15378a7d6542SBram Moolenaar 		    {
15388a7d6542SBram Moolenaar 			tv = STACK_TV_BOT(-1);
15398a7d6542SBram Moolenaar 			jump = tv2bool(tv);
15408a7d6542SBram Moolenaar 			if (when == JUMP_IF_FALSE
15418a7d6542SBram Moolenaar 					     || when == JUMP_AND_KEEP_IF_FALSE)
15428a7d6542SBram Moolenaar 			    jump = !jump;
1543777770fbSBram Moolenaar 			if (when == JUMP_IF_FALSE || !jump)
15448a7d6542SBram Moolenaar 			{
15458a7d6542SBram Moolenaar 			    // drop the value from the stack
15468a7d6542SBram Moolenaar 			    clear_tv(tv);
15478a7d6542SBram Moolenaar 			    --ectx.ec_stack.ga_len;
15488a7d6542SBram Moolenaar 			}
15498a7d6542SBram Moolenaar 		    }
15508a7d6542SBram Moolenaar 		    if (jump)
15518a7d6542SBram Moolenaar 			ectx.ec_iidx = iptr->isn_arg.jump.jump_where;
15528a7d6542SBram Moolenaar 		}
15538a7d6542SBram Moolenaar 		break;
15548a7d6542SBram Moolenaar 
15558a7d6542SBram Moolenaar 	    // top of a for loop
15568a7d6542SBram Moolenaar 	    case ISN_FOR:
15578a7d6542SBram Moolenaar 		{
15588a7d6542SBram Moolenaar 		    list_T	*list = STACK_TV_BOT(-1)->vval.v_list;
15598a7d6542SBram Moolenaar 		    typval_T	*idxtv =
15608a7d6542SBram Moolenaar 				   STACK_TV_VAR(iptr->isn_arg.forloop.for_idx);
15618a7d6542SBram Moolenaar 
15628a7d6542SBram Moolenaar 		    // push the next item from the list
15638a7d6542SBram Moolenaar 		    if (ga_grow(&ectx.ec_stack, 1) == FAIL)
15648a7d6542SBram Moolenaar 			goto failed;
15658a7d6542SBram Moolenaar 		    if (++idxtv->vval.v_number >= list->lv_len)
15668a7d6542SBram Moolenaar 			// past the end of the list, jump to "endfor"
15678a7d6542SBram Moolenaar 			ectx.ec_iidx = iptr->isn_arg.forloop.for_end;
15688a7d6542SBram Moolenaar 		    else if (list->lv_first == &range_list_item)
15698a7d6542SBram Moolenaar 		    {
15708a7d6542SBram Moolenaar 			// non-materialized range() list
15718a7d6542SBram Moolenaar 			tv = STACK_TV_BOT(0);
15728a7d6542SBram Moolenaar 			tv->v_type = VAR_NUMBER;
15738a7d6542SBram Moolenaar 			tv->vval.v_number = list_find_nr(
15748a7d6542SBram Moolenaar 					     list, idxtv->vval.v_number, NULL);
15758a7d6542SBram Moolenaar 			++ectx.ec_stack.ga_len;
15768a7d6542SBram Moolenaar 		    }
15778a7d6542SBram Moolenaar 		    else
15788a7d6542SBram Moolenaar 		    {
15798a7d6542SBram Moolenaar 			listitem_T *li = list_find(list, idxtv->vval.v_number);
15808a7d6542SBram Moolenaar 
15818a7d6542SBram Moolenaar 			if (li == NULL)
15828a7d6542SBram Moolenaar 			    goto failed;
15838a7d6542SBram Moolenaar 			copy_tv(&li->li_tv, STACK_TV_BOT(0));
15848a7d6542SBram Moolenaar 			++ectx.ec_stack.ga_len;
15858a7d6542SBram Moolenaar 		    }
15868a7d6542SBram Moolenaar 		}
15878a7d6542SBram Moolenaar 		break;
15888a7d6542SBram Moolenaar 
15898a7d6542SBram Moolenaar 	    // start of ":try" block
15908a7d6542SBram Moolenaar 	    case ISN_TRY:
15918a7d6542SBram Moolenaar 		{
159220431c9dSBram Moolenaar 		    trycmd_T    *trycmd = NULL;
159320431c9dSBram Moolenaar 
15948a7d6542SBram Moolenaar 		    if (ga_grow(&ectx.ec_trystack, 1) == FAIL)
15958a7d6542SBram Moolenaar 			goto failed;
15968a7d6542SBram Moolenaar 		    trycmd = ((trycmd_T *)ectx.ec_trystack.ga_data)
15978a7d6542SBram Moolenaar 						     + ectx.ec_trystack.ga_len;
15988a7d6542SBram Moolenaar 		    ++ectx.ec_trystack.ga_len;
15998a7d6542SBram Moolenaar 		    ++trylevel;
1600bf67ea1aSBram Moolenaar 		    trycmd->tcd_frame_idx = ectx.ec_frame_idx;
16018a7d6542SBram Moolenaar 		    trycmd->tcd_catch_idx = iptr->isn_arg.try.try_catch;
16028a7d6542SBram Moolenaar 		    trycmd->tcd_finally_idx = iptr->isn_arg.try.try_finally;
1603f575adffSBram Moolenaar 		    trycmd->tcd_caught = FALSE;
16048a7d6542SBram Moolenaar 		}
16058a7d6542SBram Moolenaar 		break;
16068a7d6542SBram Moolenaar 
16078a7d6542SBram Moolenaar 	    case ISN_PUSHEXC:
16088a7d6542SBram Moolenaar 		if (current_exception == NULL)
16098a7d6542SBram Moolenaar 		{
16108a7d6542SBram Moolenaar 		    iemsg("Evaluating catch while current_exception is NULL");
16118a7d6542SBram Moolenaar 		    goto failed;
16128a7d6542SBram Moolenaar 		}
16138a7d6542SBram Moolenaar 		if (ga_grow(&ectx.ec_stack, 1) == FAIL)
16148a7d6542SBram Moolenaar 		    goto failed;
16158a7d6542SBram Moolenaar 		tv = STACK_TV_BOT(0);
16168a7d6542SBram Moolenaar 		++ectx.ec_stack.ga_len;
16178a7d6542SBram Moolenaar 		tv->v_type = VAR_STRING;
16188a7d6542SBram Moolenaar 		tv->vval.v_string = vim_strsave(
16198a7d6542SBram Moolenaar 					   (char_u *)current_exception->value);
16208a7d6542SBram Moolenaar 		break;
16218a7d6542SBram Moolenaar 
16228a7d6542SBram Moolenaar 	    case ISN_CATCH:
16238a7d6542SBram Moolenaar 		{
16248a7d6542SBram Moolenaar 		    garray_T	*trystack = &ectx.ec_trystack;
16258a7d6542SBram Moolenaar 
16268a7d6542SBram Moolenaar 		    if (trystack->ga_len > 0)
16278a7d6542SBram Moolenaar 		    {
162820431c9dSBram Moolenaar 			trycmd_T    *trycmd = ((trycmd_T *)trystack->ga_data)
16298a7d6542SBram Moolenaar 							+ trystack->ga_len - 1;
16308a7d6542SBram Moolenaar 			trycmd->tcd_caught = TRUE;
16318a7d6542SBram Moolenaar 		    }
16328a7d6542SBram Moolenaar 		    did_emsg = got_int = did_throw = FALSE;
16338a7d6542SBram Moolenaar 		    catch_exception(current_exception);
16348a7d6542SBram Moolenaar 		}
16358a7d6542SBram Moolenaar 		break;
16368a7d6542SBram Moolenaar 
16378a7d6542SBram Moolenaar 	    // end of ":try" block
16388a7d6542SBram Moolenaar 	    case ISN_ENDTRY:
16398a7d6542SBram Moolenaar 		{
16408a7d6542SBram Moolenaar 		    garray_T	*trystack = &ectx.ec_trystack;
16418a7d6542SBram Moolenaar 
16428a7d6542SBram Moolenaar 		    if (trystack->ga_len > 0)
16438a7d6542SBram Moolenaar 		    {
164420431c9dSBram Moolenaar 			trycmd_T    *trycmd = NULL;
164520431c9dSBram Moolenaar 
16468a7d6542SBram Moolenaar 			--trystack->ga_len;
16478a7d6542SBram Moolenaar 			--trylevel;
16488a7d6542SBram Moolenaar 			trycmd = ((trycmd_T *)trystack->ga_data)
16498a7d6542SBram Moolenaar 							    + trystack->ga_len;
1650f575adffSBram Moolenaar 			if (trycmd->tcd_caught && current_exception != NULL)
16518a7d6542SBram Moolenaar 			{
16528a7d6542SBram Moolenaar 			    // discard the exception
16538a7d6542SBram Moolenaar 			    if (caught_stack == current_exception)
16548a7d6542SBram Moolenaar 				caught_stack = caught_stack->caught;
16558a7d6542SBram Moolenaar 			    discard_current_exception();
16568a7d6542SBram Moolenaar 			}
16578a7d6542SBram Moolenaar 
16588a7d6542SBram Moolenaar 			if (trycmd->tcd_return)
16598a7d6542SBram Moolenaar 			{
16608a7d6542SBram Moolenaar 			    // Restore previous function. If the frame pointer
16618a7d6542SBram Moolenaar 			    // is zero then there is none and we are done.
1662bf67ea1aSBram Moolenaar 			    if (ectx.ec_frame_idx == initial_frame_idx)
1663bf67ea1aSBram Moolenaar 			    {
1664bf67ea1aSBram Moolenaar 				if (handle_closure_in_use(&ectx, FALSE) == FAIL)
1665bf67ea1aSBram Moolenaar 				    goto failed;
16668a7d6542SBram Moolenaar 				goto done;
1667bf67ea1aSBram Moolenaar 			    }
16688a7d6542SBram Moolenaar 
1669bf67ea1aSBram Moolenaar 			    if (func_return(&ectx) == FAIL)
1670bf67ea1aSBram Moolenaar 				goto failed;
16718a7d6542SBram Moolenaar 			}
16728a7d6542SBram Moolenaar 		    }
16738a7d6542SBram Moolenaar 		}
16748a7d6542SBram Moolenaar 		break;
16758a7d6542SBram Moolenaar 
16768a7d6542SBram Moolenaar 	    case ISN_THROW:
16778a7d6542SBram Moolenaar 		--ectx.ec_stack.ga_len;
16788a7d6542SBram Moolenaar 		tv = STACK_TV_BOT(0);
16798a7d6542SBram Moolenaar 		if (throw_exception(tv->vval.v_string, ET_USER, NULL) == FAIL)
16808a7d6542SBram Moolenaar 		{
16818a7d6542SBram Moolenaar 		    vim_free(tv->vval.v_string);
16828a7d6542SBram Moolenaar 		    goto failed;
16838a7d6542SBram Moolenaar 		}
16848a7d6542SBram Moolenaar 		did_throw = TRUE;
16858a7d6542SBram Moolenaar 		break;
16868a7d6542SBram Moolenaar 
16878a7d6542SBram Moolenaar 	    // compare with special values
16888a7d6542SBram Moolenaar 	    case ISN_COMPAREBOOL:
16898a7d6542SBram Moolenaar 	    case ISN_COMPARESPECIAL:
16908a7d6542SBram Moolenaar 		{
16918a7d6542SBram Moolenaar 		    typval_T	*tv1 = STACK_TV_BOT(-2);
16928a7d6542SBram Moolenaar 		    typval_T	*tv2 = STACK_TV_BOT(-1);
16938a7d6542SBram Moolenaar 		    varnumber_T arg1 = tv1->vval.v_number;
16948a7d6542SBram Moolenaar 		    varnumber_T arg2 = tv2->vval.v_number;
16958a7d6542SBram Moolenaar 		    int		res;
16968a7d6542SBram Moolenaar 
16978a7d6542SBram Moolenaar 		    switch (iptr->isn_arg.op.op_type)
16988a7d6542SBram Moolenaar 		    {
16998a7d6542SBram Moolenaar 			case EXPR_EQUAL: res = arg1 == arg2; break;
17008a7d6542SBram Moolenaar 			case EXPR_NEQUAL: res = arg1 != arg2; break;
17018a7d6542SBram Moolenaar 			default: res = 0; break;
17028a7d6542SBram Moolenaar 		    }
17038a7d6542SBram Moolenaar 
17048a7d6542SBram Moolenaar 		    --ectx.ec_stack.ga_len;
17058a7d6542SBram Moolenaar 		    tv1->v_type = VAR_BOOL;
17068a7d6542SBram Moolenaar 		    tv1->vval.v_number = res ? VVAL_TRUE : VVAL_FALSE;
17078a7d6542SBram Moolenaar 		}
17088a7d6542SBram Moolenaar 		break;
17098a7d6542SBram Moolenaar 
17108a7d6542SBram Moolenaar 	    // Operation with two number arguments
17118a7d6542SBram Moolenaar 	    case ISN_OPNR:
17128a7d6542SBram Moolenaar 	    case ISN_COMPARENR:
17138a7d6542SBram Moolenaar 		{
17148a7d6542SBram Moolenaar 		    typval_T	*tv1 = STACK_TV_BOT(-2);
17158a7d6542SBram Moolenaar 		    typval_T	*tv2 = STACK_TV_BOT(-1);
17168a7d6542SBram Moolenaar 		    varnumber_T arg1 = tv1->vval.v_number;
17178a7d6542SBram Moolenaar 		    varnumber_T arg2 = tv2->vval.v_number;
17188a7d6542SBram Moolenaar 		    varnumber_T res;
17198a7d6542SBram Moolenaar 
17208a7d6542SBram Moolenaar 		    switch (iptr->isn_arg.op.op_type)
17218a7d6542SBram Moolenaar 		    {
17228a7d6542SBram Moolenaar 			case EXPR_MULT: res = arg1 * arg2; break;
17238a7d6542SBram Moolenaar 			case EXPR_DIV: res = arg1 / arg2; break;
17248a7d6542SBram Moolenaar 			case EXPR_REM: res = arg1 % arg2; break;
17258a7d6542SBram Moolenaar 			case EXPR_SUB: res = arg1 - arg2; break;
17268a7d6542SBram Moolenaar 			case EXPR_ADD: res = arg1 + arg2; break;
17278a7d6542SBram Moolenaar 
17288a7d6542SBram Moolenaar 			case EXPR_EQUAL: res = arg1 == arg2; break;
17298a7d6542SBram Moolenaar 			case EXPR_NEQUAL: res = arg1 != arg2; break;
17308a7d6542SBram Moolenaar 			case EXPR_GREATER: res = arg1 > arg2; break;
17318a7d6542SBram Moolenaar 			case EXPR_GEQUAL: res = arg1 >= arg2; break;
17328a7d6542SBram Moolenaar 			case EXPR_SMALLER: res = arg1 < arg2; break;
17338a7d6542SBram Moolenaar 			case EXPR_SEQUAL: res = arg1 <= arg2; break;
17348a7d6542SBram Moolenaar 			default: res = 0; break;
17358a7d6542SBram Moolenaar 		    }
17368a7d6542SBram Moolenaar 
17378a7d6542SBram Moolenaar 		    --ectx.ec_stack.ga_len;
17388a7d6542SBram Moolenaar 		    if (iptr->isn_type == ISN_COMPARENR)
17398a7d6542SBram Moolenaar 		    {
17408a7d6542SBram Moolenaar 			tv1->v_type = VAR_BOOL;
17418a7d6542SBram Moolenaar 			tv1->vval.v_number = res ? VVAL_TRUE : VVAL_FALSE;
17428a7d6542SBram Moolenaar 		    }
17438a7d6542SBram Moolenaar 		    else
17448a7d6542SBram Moolenaar 			tv1->vval.v_number = res;
17458a7d6542SBram Moolenaar 		}
17468a7d6542SBram Moolenaar 		break;
17478a7d6542SBram Moolenaar 
17488a7d6542SBram Moolenaar 	    // Computation with two float arguments
17498a7d6542SBram Moolenaar 	    case ISN_OPFLOAT:
17508a7d6542SBram Moolenaar 	    case ISN_COMPAREFLOAT:
1751a5d5953dSBram Moolenaar #ifdef FEAT_FLOAT
17528a7d6542SBram Moolenaar 		{
17538a7d6542SBram Moolenaar 		    typval_T	*tv1 = STACK_TV_BOT(-2);
17548a7d6542SBram Moolenaar 		    typval_T	*tv2 = STACK_TV_BOT(-1);
17558a7d6542SBram Moolenaar 		    float_T	arg1 = tv1->vval.v_float;
17568a7d6542SBram Moolenaar 		    float_T	arg2 = tv2->vval.v_float;
17578a7d6542SBram Moolenaar 		    float_T	res = 0;
17588a7d6542SBram Moolenaar 		    int		cmp = FALSE;
17598a7d6542SBram Moolenaar 
17608a7d6542SBram Moolenaar 		    switch (iptr->isn_arg.op.op_type)
17618a7d6542SBram Moolenaar 		    {
17628a7d6542SBram Moolenaar 			case EXPR_MULT: res = arg1 * arg2; break;
17638a7d6542SBram Moolenaar 			case EXPR_DIV: res = arg1 / arg2; break;
17648a7d6542SBram Moolenaar 			case EXPR_SUB: res = arg1 - arg2; break;
17658a7d6542SBram Moolenaar 			case EXPR_ADD: res = arg1 + arg2; break;
17668a7d6542SBram Moolenaar 
17678a7d6542SBram Moolenaar 			case EXPR_EQUAL: cmp = arg1 == arg2; break;
17688a7d6542SBram Moolenaar 			case EXPR_NEQUAL: cmp = arg1 != arg2; break;
17698a7d6542SBram Moolenaar 			case EXPR_GREATER: cmp = arg1 > arg2; break;
17708a7d6542SBram Moolenaar 			case EXPR_GEQUAL: cmp = arg1 >= arg2; break;
17718a7d6542SBram Moolenaar 			case EXPR_SMALLER: cmp = arg1 < arg2; break;
17728a7d6542SBram Moolenaar 			case EXPR_SEQUAL: cmp = arg1 <= arg2; break;
17738a7d6542SBram Moolenaar 			default: cmp = 0; break;
17748a7d6542SBram Moolenaar 		    }
17758a7d6542SBram Moolenaar 		    --ectx.ec_stack.ga_len;
17768a7d6542SBram Moolenaar 		    if (iptr->isn_type == ISN_COMPAREFLOAT)
17778a7d6542SBram Moolenaar 		    {
17788a7d6542SBram Moolenaar 			tv1->v_type = VAR_BOOL;
17798a7d6542SBram Moolenaar 			tv1->vval.v_number = cmp ? VVAL_TRUE : VVAL_FALSE;
17808a7d6542SBram Moolenaar 		    }
17818a7d6542SBram Moolenaar 		    else
17828a7d6542SBram Moolenaar 			tv1->vval.v_float = res;
17838a7d6542SBram Moolenaar 		}
1784a5d5953dSBram Moolenaar #endif
17858a7d6542SBram Moolenaar 		break;
17868a7d6542SBram Moolenaar 
17878a7d6542SBram Moolenaar 	    case ISN_COMPARELIST:
17888a7d6542SBram Moolenaar 		{
17898a7d6542SBram Moolenaar 		    typval_T	*tv1 = STACK_TV_BOT(-2);
17908a7d6542SBram Moolenaar 		    typval_T	*tv2 = STACK_TV_BOT(-1);
17918a7d6542SBram Moolenaar 		    list_T	*arg1 = tv1->vval.v_list;
17928a7d6542SBram Moolenaar 		    list_T	*arg2 = tv2->vval.v_list;
17938a7d6542SBram Moolenaar 		    int		cmp = FALSE;
17948a7d6542SBram Moolenaar 		    int		ic = iptr->isn_arg.op.op_ic;
17958a7d6542SBram Moolenaar 
17968a7d6542SBram Moolenaar 		    switch (iptr->isn_arg.op.op_type)
17978a7d6542SBram Moolenaar 		    {
17988a7d6542SBram Moolenaar 			case EXPR_EQUAL: cmp =
17998a7d6542SBram Moolenaar 				      list_equal(arg1, arg2, ic, FALSE); break;
18008a7d6542SBram Moolenaar 			case EXPR_NEQUAL: cmp =
18018a7d6542SBram Moolenaar 				     !list_equal(arg1, arg2, ic, FALSE); break;
18028a7d6542SBram Moolenaar 			case EXPR_IS: cmp = arg1 == arg2; break;
18038a7d6542SBram Moolenaar 			case EXPR_ISNOT: cmp = arg1 != arg2; break;
18048a7d6542SBram Moolenaar 			default: cmp = 0; break;
18058a7d6542SBram Moolenaar 		    }
18068a7d6542SBram Moolenaar 		    --ectx.ec_stack.ga_len;
18078a7d6542SBram Moolenaar 		    clear_tv(tv1);
18088a7d6542SBram Moolenaar 		    clear_tv(tv2);
18098a7d6542SBram Moolenaar 		    tv1->v_type = VAR_BOOL;
18108a7d6542SBram Moolenaar 		    tv1->vval.v_number = cmp ? VVAL_TRUE : VVAL_FALSE;
18118a7d6542SBram Moolenaar 		}
18128a7d6542SBram Moolenaar 		break;
18138a7d6542SBram Moolenaar 
18148a7d6542SBram Moolenaar 	    case ISN_COMPAREBLOB:
18158a7d6542SBram Moolenaar 		{
18168a7d6542SBram Moolenaar 		    typval_T	*tv1 = STACK_TV_BOT(-2);
18178a7d6542SBram Moolenaar 		    typval_T	*tv2 = STACK_TV_BOT(-1);
18188a7d6542SBram Moolenaar 		    blob_T	*arg1 = tv1->vval.v_blob;
18198a7d6542SBram Moolenaar 		    blob_T	*arg2 = tv2->vval.v_blob;
18208a7d6542SBram Moolenaar 		    int		cmp = FALSE;
18218a7d6542SBram Moolenaar 
18228a7d6542SBram Moolenaar 		    switch (iptr->isn_arg.op.op_type)
18238a7d6542SBram Moolenaar 		    {
18248a7d6542SBram Moolenaar 			case EXPR_EQUAL: cmp = blob_equal(arg1, arg2); break;
18258a7d6542SBram Moolenaar 			case EXPR_NEQUAL: cmp = !blob_equal(arg1, arg2); break;
18268a7d6542SBram Moolenaar 			case EXPR_IS: cmp = arg1 == arg2; break;
18278a7d6542SBram Moolenaar 			case EXPR_ISNOT: cmp = arg1 != arg2; break;
18288a7d6542SBram Moolenaar 			default: cmp = 0; break;
18298a7d6542SBram Moolenaar 		    }
18308a7d6542SBram Moolenaar 		    --ectx.ec_stack.ga_len;
18318a7d6542SBram Moolenaar 		    clear_tv(tv1);
18328a7d6542SBram Moolenaar 		    clear_tv(tv2);
18338a7d6542SBram Moolenaar 		    tv1->v_type = VAR_BOOL;
18348a7d6542SBram Moolenaar 		    tv1->vval.v_number = cmp ? VVAL_TRUE : VVAL_FALSE;
18358a7d6542SBram Moolenaar 		}
18368a7d6542SBram Moolenaar 		break;
18378a7d6542SBram Moolenaar 
18388a7d6542SBram Moolenaar 		// TODO: handle separately
18398a7d6542SBram Moolenaar 	    case ISN_COMPARESTRING:
18408a7d6542SBram Moolenaar 	    case ISN_COMPAREDICT:
18418a7d6542SBram Moolenaar 	    case ISN_COMPAREFUNC:
18428a7d6542SBram Moolenaar 	    case ISN_COMPAREANY:
18438a7d6542SBram Moolenaar 		{
18448a7d6542SBram Moolenaar 		    typval_T	*tv1 = STACK_TV_BOT(-2);
18458a7d6542SBram Moolenaar 		    typval_T	*tv2 = STACK_TV_BOT(-1);
18468a7d6542SBram Moolenaar 		    exptype_T	exptype = iptr->isn_arg.op.op_type;
18478a7d6542SBram Moolenaar 		    int		ic = iptr->isn_arg.op.op_ic;
18488a7d6542SBram Moolenaar 
18498a7d6542SBram Moolenaar 		    typval_compare(tv1, tv2, exptype, ic);
18508a7d6542SBram Moolenaar 		    clear_tv(tv2);
18518a7d6542SBram Moolenaar 		    tv1->v_type = VAR_BOOL;
18528a7d6542SBram Moolenaar 		    tv1->vval.v_number = tv1->vval.v_number
18538a7d6542SBram Moolenaar 						      ? VVAL_TRUE : VVAL_FALSE;
18548a7d6542SBram Moolenaar 		    --ectx.ec_stack.ga_len;
18558a7d6542SBram Moolenaar 		}
18568a7d6542SBram Moolenaar 		break;
18578a7d6542SBram Moolenaar 
18588a7d6542SBram Moolenaar 	    case ISN_ADDLIST:
18598a7d6542SBram Moolenaar 	    case ISN_ADDBLOB:
18608a7d6542SBram Moolenaar 		{
18618a7d6542SBram Moolenaar 		    typval_T *tv1 = STACK_TV_BOT(-2);
18628a7d6542SBram Moolenaar 		    typval_T *tv2 = STACK_TV_BOT(-1);
18638a7d6542SBram Moolenaar 
18648a7d6542SBram Moolenaar 		    if (iptr->isn_type == ISN_ADDLIST)
18658a7d6542SBram Moolenaar 			eval_addlist(tv1, tv2);
18668a7d6542SBram Moolenaar 		    else
18678a7d6542SBram Moolenaar 			eval_addblob(tv1, tv2);
18688a7d6542SBram Moolenaar 		    clear_tv(tv2);
18698a7d6542SBram Moolenaar 		    --ectx.ec_stack.ga_len;
18708a7d6542SBram Moolenaar 		}
18718a7d6542SBram Moolenaar 		break;
18728a7d6542SBram Moolenaar 
18738a7d6542SBram Moolenaar 	    // Computation with two arguments of unknown type
18748a7d6542SBram Moolenaar 	    case ISN_OPANY:
18758a7d6542SBram Moolenaar 		{
18768a7d6542SBram Moolenaar 		    typval_T	*tv1 = STACK_TV_BOT(-2);
18778a7d6542SBram Moolenaar 		    typval_T	*tv2 = STACK_TV_BOT(-1);
18788a7d6542SBram Moolenaar 		    varnumber_T	n1, n2;
18798a7d6542SBram Moolenaar #ifdef FEAT_FLOAT
18808a7d6542SBram Moolenaar 		    float_T	f1 = 0, f2 = 0;
18818a7d6542SBram Moolenaar #endif
18828a7d6542SBram Moolenaar 		    int		error = FALSE;
18838a7d6542SBram Moolenaar 
18848a7d6542SBram Moolenaar 		    if (iptr->isn_arg.op.op_type == EXPR_ADD)
18858a7d6542SBram Moolenaar 		    {
18868a7d6542SBram Moolenaar 			if (tv1->v_type == VAR_LIST && tv2->v_type == VAR_LIST)
18878a7d6542SBram Moolenaar 			{
18888a7d6542SBram Moolenaar 			    eval_addlist(tv1, tv2);
18898a7d6542SBram Moolenaar 			    clear_tv(tv2);
18908a7d6542SBram Moolenaar 			    --ectx.ec_stack.ga_len;
18918a7d6542SBram Moolenaar 			    break;
18928a7d6542SBram Moolenaar 			}
18938a7d6542SBram Moolenaar 			else if (tv1->v_type == VAR_BLOB
18948a7d6542SBram Moolenaar 						    && tv2->v_type == VAR_BLOB)
18958a7d6542SBram Moolenaar 			{
18968a7d6542SBram Moolenaar 			    eval_addblob(tv1, tv2);
18978a7d6542SBram Moolenaar 			    clear_tv(tv2);
18988a7d6542SBram Moolenaar 			    --ectx.ec_stack.ga_len;
18998a7d6542SBram Moolenaar 			    break;
19008a7d6542SBram Moolenaar 			}
19018a7d6542SBram Moolenaar 		    }
19028a7d6542SBram Moolenaar #ifdef FEAT_FLOAT
19038a7d6542SBram Moolenaar 		    if (tv1->v_type == VAR_FLOAT)
19048a7d6542SBram Moolenaar 		    {
19058a7d6542SBram Moolenaar 			f1 = tv1->vval.v_float;
19068a7d6542SBram Moolenaar 			n1 = 0;
19078a7d6542SBram Moolenaar 		    }
19088a7d6542SBram Moolenaar 		    else
19098a7d6542SBram Moolenaar #endif
19108a7d6542SBram Moolenaar 		    {
19118a7d6542SBram Moolenaar 			n1 = tv_get_number_chk(tv1, &error);
19128a7d6542SBram Moolenaar 			if (error)
19138a7d6542SBram Moolenaar 			    goto failed;
19148a7d6542SBram Moolenaar #ifdef FEAT_FLOAT
19158a7d6542SBram Moolenaar 			if (tv2->v_type == VAR_FLOAT)
19168a7d6542SBram Moolenaar 			    f1 = n1;
19178a7d6542SBram Moolenaar #endif
19188a7d6542SBram Moolenaar 		    }
19198a7d6542SBram Moolenaar #ifdef FEAT_FLOAT
19208a7d6542SBram Moolenaar 		    if (tv2->v_type == VAR_FLOAT)
19218a7d6542SBram Moolenaar 		    {
19228a7d6542SBram Moolenaar 			f2 = tv2->vval.v_float;
19238a7d6542SBram Moolenaar 			n2 = 0;
19248a7d6542SBram Moolenaar 		    }
19258a7d6542SBram Moolenaar 		    else
19268a7d6542SBram Moolenaar #endif
19278a7d6542SBram Moolenaar 		    {
19288a7d6542SBram Moolenaar 			n2 = tv_get_number_chk(tv2, &error);
19298a7d6542SBram Moolenaar 			if (error)
19308a7d6542SBram Moolenaar 			    goto failed;
19318a7d6542SBram Moolenaar #ifdef FEAT_FLOAT
19328a7d6542SBram Moolenaar 			if (tv1->v_type == VAR_FLOAT)
19338a7d6542SBram Moolenaar 			    f2 = n2;
19348a7d6542SBram Moolenaar #endif
19358a7d6542SBram Moolenaar 		    }
19368a7d6542SBram Moolenaar #ifdef FEAT_FLOAT
19378a7d6542SBram Moolenaar 		    // if there is a float on either side the result is a float
19388a7d6542SBram Moolenaar 		    if (tv1->v_type == VAR_FLOAT || tv2->v_type == VAR_FLOAT)
19398a7d6542SBram Moolenaar 		    {
19408a7d6542SBram Moolenaar 			switch (iptr->isn_arg.op.op_type)
19418a7d6542SBram Moolenaar 			{
19428a7d6542SBram Moolenaar 			    case EXPR_MULT: f1 = f1 * f2; break;
19438a7d6542SBram Moolenaar 			    case EXPR_DIV:  f1 = f1 / f2; break;
19448a7d6542SBram Moolenaar 			    case EXPR_SUB:  f1 = f1 - f2; break;
19458a7d6542SBram Moolenaar 			    case EXPR_ADD:  f1 = f1 + f2; break;
19468a7d6542SBram Moolenaar 			    default: emsg(_(e_modulus)); goto failed;
19478a7d6542SBram Moolenaar 			}
19488a7d6542SBram Moolenaar 			clear_tv(tv1);
19498a7d6542SBram Moolenaar 			clear_tv(tv2);
19508a7d6542SBram Moolenaar 			tv1->v_type = VAR_FLOAT;
19518a7d6542SBram Moolenaar 			tv1->vval.v_float = f1;
19528a7d6542SBram Moolenaar 			--ectx.ec_stack.ga_len;
19538a7d6542SBram Moolenaar 		    }
19548a7d6542SBram Moolenaar 		    else
19558a7d6542SBram Moolenaar #endif
19568a7d6542SBram Moolenaar 		    {
19578a7d6542SBram Moolenaar 			switch (iptr->isn_arg.op.op_type)
19588a7d6542SBram Moolenaar 			{
19598a7d6542SBram Moolenaar 			    case EXPR_MULT: n1 = n1 * n2; break;
19608a7d6542SBram Moolenaar 			    case EXPR_DIV:  n1 = num_divide(n1, n2); break;
19618a7d6542SBram Moolenaar 			    case EXPR_SUB:  n1 = n1 - n2; break;
19628a7d6542SBram Moolenaar 			    case EXPR_ADD:  n1 = n1 + n2; break;
19638a7d6542SBram Moolenaar 			    default:	    n1 = num_modulus(n1, n2); break;
19648a7d6542SBram Moolenaar 			}
19658a7d6542SBram Moolenaar 			clear_tv(tv1);
19668a7d6542SBram Moolenaar 			clear_tv(tv2);
19678a7d6542SBram Moolenaar 			tv1->v_type = VAR_NUMBER;
19688a7d6542SBram Moolenaar 			tv1->vval.v_number = n1;
19698a7d6542SBram Moolenaar 			--ectx.ec_stack.ga_len;
19708a7d6542SBram Moolenaar 		    }
19718a7d6542SBram Moolenaar 		}
19728a7d6542SBram Moolenaar 		break;
19738a7d6542SBram Moolenaar 
19748a7d6542SBram Moolenaar 	    case ISN_CONCAT:
19758a7d6542SBram Moolenaar 		{
19768a7d6542SBram Moolenaar 		    char_u *str1 = STACK_TV_BOT(-2)->vval.v_string;
19778a7d6542SBram Moolenaar 		    char_u *str2 = STACK_TV_BOT(-1)->vval.v_string;
19788a7d6542SBram Moolenaar 		    char_u *res;
19798a7d6542SBram Moolenaar 
19808a7d6542SBram Moolenaar 		    res = concat_str(str1, str2);
19818a7d6542SBram Moolenaar 		    clear_tv(STACK_TV_BOT(-2));
19828a7d6542SBram Moolenaar 		    clear_tv(STACK_TV_BOT(-1));
19838a7d6542SBram Moolenaar 		    --ectx.ec_stack.ga_len;
19848a7d6542SBram Moolenaar 		    STACK_TV_BOT(-1)->vval.v_string = res;
19858a7d6542SBram Moolenaar 		}
19868a7d6542SBram Moolenaar 		break;
19878a7d6542SBram Moolenaar 
19888a7d6542SBram Moolenaar 	    case ISN_INDEX:
19898a7d6542SBram Moolenaar 		{
19908a7d6542SBram Moolenaar 		    list_T	*list;
19918a7d6542SBram Moolenaar 		    varnumber_T	n;
19928a7d6542SBram Moolenaar 		    listitem_T	*li;
19938a7d6542SBram Moolenaar 
19948a7d6542SBram Moolenaar 		    // list index: list is at stack-2, index at stack-1
19958a7d6542SBram Moolenaar 		    tv = STACK_TV_BOT(-2);
19968a7d6542SBram Moolenaar 		    if (tv->v_type != VAR_LIST)
19978a7d6542SBram Moolenaar 		    {
19988a7d6542SBram Moolenaar 			emsg(_(e_listreq));
19998a7d6542SBram Moolenaar 			goto failed;
20008a7d6542SBram Moolenaar 		    }
20018a7d6542SBram Moolenaar 		    list = tv->vval.v_list;
20028a7d6542SBram Moolenaar 
20038a7d6542SBram Moolenaar 		    tv = STACK_TV_BOT(-1);
20048a7d6542SBram Moolenaar 		    if (tv->v_type != VAR_NUMBER)
20058a7d6542SBram Moolenaar 		    {
20068a7d6542SBram Moolenaar 			emsg(_(e_number_exp));
20078a7d6542SBram Moolenaar 			goto failed;
20088a7d6542SBram Moolenaar 		    }
20098a7d6542SBram Moolenaar 		    n = tv->vval.v_number;
20108a7d6542SBram Moolenaar 		    clear_tv(tv);
20118a7d6542SBram Moolenaar 		    if ((li = list_find(list, n)) == NULL)
20128a7d6542SBram Moolenaar 		    {
20138a7d6542SBram Moolenaar 			semsg(_(e_listidx), n);
20148a7d6542SBram Moolenaar 			goto failed;
20158a7d6542SBram Moolenaar 		    }
20168a7d6542SBram Moolenaar 		    --ectx.ec_stack.ga_len;
20178a7d6542SBram Moolenaar 		    clear_tv(STACK_TV_BOT(-1));
20188a7d6542SBram Moolenaar 		    copy_tv(&li->li_tv, STACK_TV_BOT(-1));
20198a7d6542SBram Moolenaar 		}
20208a7d6542SBram Moolenaar 		break;
20218a7d6542SBram Moolenaar 
20228a7d6542SBram Moolenaar 	    // dict member with string key
20238a7d6542SBram Moolenaar 	    case ISN_MEMBER:
20248a7d6542SBram Moolenaar 		{
20258a7d6542SBram Moolenaar 		    dict_T	*dict;
20268a7d6542SBram Moolenaar 		    dictitem_T	*di;
20278a7d6542SBram Moolenaar 
20288a7d6542SBram Moolenaar 		    tv = STACK_TV_BOT(-1);
20298a7d6542SBram Moolenaar 		    if (tv->v_type != VAR_DICT || tv->vval.v_dict == NULL)
20308a7d6542SBram Moolenaar 		    {
20318a7d6542SBram Moolenaar 			emsg(_(e_dictreq));
20328a7d6542SBram Moolenaar 			goto failed;
20338a7d6542SBram Moolenaar 		    }
20348a7d6542SBram Moolenaar 		    dict = tv->vval.v_dict;
20358a7d6542SBram Moolenaar 
20368a7d6542SBram Moolenaar 		    if ((di = dict_find(dict, iptr->isn_arg.string, -1))
20378a7d6542SBram Moolenaar 								       == NULL)
20388a7d6542SBram Moolenaar 		    {
20398a7d6542SBram Moolenaar 			semsg(_(e_dictkey), iptr->isn_arg.string);
20408a7d6542SBram Moolenaar 			goto failed;
20418a7d6542SBram Moolenaar 		    }
20428a7d6542SBram Moolenaar 		    clear_tv(tv);
20438a7d6542SBram Moolenaar 		    copy_tv(&di->di_tv, tv);
20448a7d6542SBram Moolenaar 		}
20458a7d6542SBram Moolenaar 		break;
20468a7d6542SBram Moolenaar 
20478a7d6542SBram Moolenaar 	    case ISN_NEGATENR:
20488a7d6542SBram Moolenaar 		tv = STACK_TV_BOT(-1);
2049c58164c5SBram Moolenaar 		if (tv->v_type != VAR_NUMBER
2050c58164c5SBram Moolenaar #ifdef FEAT_FLOAT
2051c58164c5SBram Moolenaar 			&& tv->v_type != VAR_FLOAT
2052c58164c5SBram Moolenaar #endif
2053c58164c5SBram Moolenaar 			)
2054c58164c5SBram Moolenaar 		{
2055c58164c5SBram Moolenaar 		    emsg(_(e_number_exp));
2056c58164c5SBram Moolenaar 		    goto failed;
2057c58164c5SBram Moolenaar 		}
2058c58164c5SBram Moolenaar #ifdef FEAT_FLOAT
2059c58164c5SBram Moolenaar 		if (tv->v_type == VAR_FLOAT)
2060c58164c5SBram Moolenaar 		    tv->vval.v_float = -tv->vval.v_float;
2061c58164c5SBram Moolenaar 		else
2062c58164c5SBram Moolenaar #endif
20638a7d6542SBram Moolenaar 		    tv->vval.v_number = -tv->vval.v_number;
20648a7d6542SBram Moolenaar 		break;
20658a7d6542SBram Moolenaar 
20668a7d6542SBram Moolenaar 	    case ISN_CHECKNR:
20678a7d6542SBram Moolenaar 		{
20688a7d6542SBram Moolenaar 		    int		error = FALSE;
20698a7d6542SBram Moolenaar 
20708a7d6542SBram Moolenaar 		    tv = STACK_TV_BOT(-1);
20718a7d6542SBram Moolenaar 		    if (check_not_string(tv) == FAIL)
20728a7d6542SBram Moolenaar 			goto failed;
20738a7d6542SBram Moolenaar 		    (void)tv_get_number_chk(tv, &error);
20748a7d6542SBram Moolenaar 		    if (error)
20758a7d6542SBram Moolenaar 			goto failed;
20768a7d6542SBram Moolenaar 		}
20778a7d6542SBram Moolenaar 		break;
20788a7d6542SBram Moolenaar 
20798a7d6542SBram Moolenaar 	    case ISN_CHECKTYPE:
20808a7d6542SBram Moolenaar 		{
20818a7d6542SBram Moolenaar 		    checktype_T *ct = &iptr->isn_arg.type;
20828a7d6542SBram Moolenaar 
20838a7d6542SBram Moolenaar 		    tv = STACK_TV_BOT(ct->ct_off);
2084c8cd2b34SBram Moolenaar 		    // TODO: better type comparison
2085c8cd2b34SBram Moolenaar 		    if (tv->v_type != ct->ct_type
2086c8cd2b34SBram Moolenaar 			    && !((tv->v_type == VAR_PARTIAL
2087c8cd2b34SBram Moolenaar 						   && ct->ct_type == VAR_FUNC)
2088c8cd2b34SBram Moolenaar 				|| (tv->v_type == VAR_FUNC
2089c8cd2b34SBram Moolenaar 					       && ct->ct_type == VAR_PARTIAL)))
20908a7d6542SBram Moolenaar 		    {
20918a7d6542SBram Moolenaar 			semsg(_("E1029: Expected %s but got %s"),
20928a7d6542SBram Moolenaar 				    vartype_name(ct->ct_type),
20938a7d6542SBram Moolenaar 				    vartype_name(tv->v_type));
20948a7d6542SBram Moolenaar 			goto failed;
20958a7d6542SBram Moolenaar 		    }
20968a7d6542SBram Moolenaar 		}
20978a7d6542SBram Moolenaar 		break;
20988a7d6542SBram Moolenaar 
20998a7d6542SBram Moolenaar 	    case ISN_2BOOL:
21008a7d6542SBram Moolenaar 		{
21018a7d6542SBram Moolenaar 		    int n;
21028a7d6542SBram Moolenaar 
21038a7d6542SBram Moolenaar 		    tv = STACK_TV_BOT(-1);
21048a7d6542SBram Moolenaar 		    n = tv2bool(tv);
21058a7d6542SBram Moolenaar 		    if (iptr->isn_arg.number)  // invert
21068a7d6542SBram Moolenaar 			n = !n;
21078a7d6542SBram Moolenaar 		    clear_tv(tv);
21088a7d6542SBram Moolenaar 		    tv->v_type = VAR_BOOL;
21098a7d6542SBram Moolenaar 		    tv->vval.v_number = n ? VVAL_TRUE : VVAL_FALSE;
21108a7d6542SBram Moolenaar 		}
21118a7d6542SBram Moolenaar 		break;
21128a7d6542SBram Moolenaar 
21138a7d6542SBram Moolenaar 	    case ISN_2STRING:
21148a7d6542SBram Moolenaar 		{
21158a7d6542SBram Moolenaar 		    char_u *str;
21168a7d6542SBram Moolenaar 
21178a7d6542SBram Moolenaar 		    tv = STACK_TV_BOT(iptr->isn_arg.number);
21188a7d6542SBram Moolenaar 		    if (tv->v_type != VAR_STRING)
21198a7d6542SBram Moolenaar 		    {
21208a7d6542SBram Moolenaar 			str = typval_tostring(tv);
21218a7d6542SBram Moolenaar 			clear_tv(tv);
21228a7d6542SBram Moolenaar 			tv->v_type = VAR_STRING;
21238a7d6542SBram Moolenaar 			tv->vval.v_string = str;
21248a7d6542SBram Moolenaar 		    }
21258a7d6542SBram Moolenaar 		}
21268a7d6542SBram Moolenaar 		break;
21278a7d6542SBram Moolenaar 
21288a7d6542SBram Moolenaar 	    case ISN_DROP:
21298a7d6542SBram Moolenaar 		--ectx.ec_stack.ga_len;
21308a7d6542SBram Moolenaar 		clear_tv(STACK_TV_BOT(0));
21318a7d6542SBram Moolenaar 		break;
21328a7d6542SBram Moolenaar 	}
21338a7d6542SBram Moolenaar     }
21348a7d6542SBram Moolenaar 
21358a7d6542SBram Moolenaar done:
21368a7d6542SBram Moolenaar     // function finished, get result from the stack.
21378a7d6542SBram Moolenaar     tv = STACK_TV_BOT(-1);
21388a7d6542SBram Moolenaar     *rettv = *tv;
21398a7d6542SBram Moolenaar     tv->v_type = VAR_UNKNOWN;
21408a7d6542SBram Moolenaar     ret = OK;
21418a7d6542SBram Moolenaar 
21428a7d6542SBram Moolenaar failed:
21437eeefd4aSBram Moolenaar     // When failed need to unwind the call stack.
2144bf67ea1aSBram Moolenaar     while (ectx.ec_frame_idx != initial_frame_idx)
21457eeefd4aSBram Moolenaar 	func_return(&ectx);
21461a2f4bf6SBram Moolenaar failed_early:
2147a26b9700SBram Moolenaar     current_sctx.sc_version = save_sc_version;
2148bf67ea1aSBram Moolenaar 
2149bf67ea1aSBram Moolenaar     // Free all local variables, but not arguments.
21508a7d6542SBram Moolenaar     for (idx = 0; idx < ectx.ec_stack.ga_len; ++idx)
21518a7d6542SBram Moolenaar 	clear_tv(STACK_TV(idx));
2152bf67ea1aSBram Moolenaar 
21538a7d6542SBram Moolenaar     vim_free(ectx.ec_stack.ga_data);
215420431c9dSBram Moolenaar     vim_free(ectx.ec_trystack.ga_data);
21558a7d6542SBram Moolenaar     return ret;
21568a7d6542SBram Moolenaar }
21578a7d6542SBram Moolenaar 
21588a7d6542SBram Moolenaar /*
21598a7d6542SBram Moolenaar  * ":dissassemble".
2160777770fbSBram Moolenaar  * We don't really need this at runtime, but we do have tests that require it,
2161777770fbSBram Moolenaar  * so always include this.
21628a7d6542SBram Moolenaar  */
21638a7d6542SBram Moolenaar     void
21648a7d6542SBram Moolenaar ex_disassemble(exarg_T *eap)
21658a7d6542SBram Moolenaar {
216621456cdcSBram Moolenaar     char_u	*arg = eap->arg;
21670f18b6d1SBram Moolenaar     char_u	*fname;
21680f18b6d1SBram Moolenaar     ufunc_T	*ufunc;
21698a7d6542SBram Moolenaar     dfunc_T	*dfunc;
21708a7d6542SBram Moolenaar     isn_T	*instr;
21718a7d6542SBram Moolenaar     int		current;
21728a7d6542SBram Moolenaar     int		line_idx = 0;
21738a7d6542SBram Moolenaar     int		prev_current = 0;
21744c17ad94SBram Moolenaar     int		is_global = FALSE;
21758a7d6542SBram Moolenaar 
21764c17ad94SBram Moolenaar     fname = trans_function_name(&arg, &is_global, FALSE,
2177b68b346eSBram Moolenaar 			    TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD, NULL, NULL);
217821456cdcSBram Moolenaar     if (fname == NULL)
217921456cdcSBram Moolenaar     {
218021456cdcSBram Moolenaar 	semsg(_(e_invarg2), eap->arg);
218121456cdcSBram Moolenaar 	return;
218221456cdcSBram Moolenaar     }
218321456cdcSBram Moolenaar 
21844c17ad94SBram Moolenaar     ufunc = find_func(fname, is_global, NULL);
2185a26b9700SBram Moolenaar     if (ufunc == NULL)
2186a26b9700SBram Moolenaar     {
2187a26b9700SBram Moolenaar 	char_u *p = untrans_function_name(fname);
2188a26b9700SBram Moolenaar 
2189a26b9700SBram Moolenaar 	if (p != NULL)
2190a26b9700SBram Moolenaar 	    // Try again without making it script-local.
21914c17ad94SBram Moolenaar 	    ufunc = find_func(p, FALSE, NULL);
2192a26b9700SBram Moolenaar     }
21930f18b6d1SBram Moolenaar     vim_free(fname);
21948a7d6542SBram Moolenaar     if (ufunc == NULL)
21958a7d6542SBram Moolenaar     {
2196df2ecddfSBram Moolenaar 	semsg(_("E1061: Cannot find function %s"), eap->arg);
21978a7d6542SBram Moolenaar 	return;
21988a7d6542SBram Moolenaar     }
21998a7d6542SBram Moolenaar     if (ufunc->uf_dfunc_idx < 0)
22008a7d6542SBram Moolenaar     {
2201df2ecddfSBram Moolenaar 	semsg(_("E1062: Function %s is not compiled"), eap->arg);
22028a7d6542SBram Moolenaar 	return;
22038a7d6542SBram Moolenaar     }
22048a7d6542SBram Moolenaar     if (ufunc->uf_name_exp != NULL)
22058a7d6542SBram Moolenaar 	msg((char *)ufunc->uf_name_exp);
22068a7d6542SBram Moolenaar     else
22078a7d6542SBram Moolenaar 	msg((char *)ufunc->uf_name);
22088a7d6542SBram Moolenaar 
22098a7d6542SBram Moolenaar     dfunc = ((dfunc_T *)def_functions.ga_data) + ufunc->uf_dfunc_idx;
22108a7d6542SBram Moolenaar     instr = dfunc->df_instr;
22118a7d6542SBram Moolenaar     for (current = 0; current < dfunc->df_instr_count; ++current)
22128a7d6542SBram Moolenaar     {
22138a7d6542SBram Moolenaar 	isn_T	    *iptr = &instr[current];
2214f2460a3aSBram Moolenaar 	char	    *line;
22158a7d6542SBram Moolenaar 
22168a7d6542SBram Moolenaar 	while (line_idx < iptr->isn_lnum && line_idx < ufunc->uf_lines.ga_len)
22178a7d6542SBram Moolenaar 	{
22188a7d6542SBram Moolenaar 	    if (current > prev_current)
22198a7d6542SBram Moolenaar 	    {
22208a7d6542SBram Moolenaar 		msg_puts("\n\n");
22218a7d6542SBram Moolenaar 		prev_current = current;
22228a7d6542SBram Moolenaar 	    }
2223f2460a3aSBram Moolenaar 	    line = ((char **)ufunc->uf_lines.ga_data)[line_idx++];
2224f2460a3aSBram Moolenaar 	    if (line != NULL)
2225f2460a3aSBram Moolenaar 		msg(line);
22268a7d6542SBram Moolenaar 	}
22278a7d6542SBram Moolenaar 
22288a7d6542SBram Moolenaar 	switch (iptr->isn_type)
22298a7d6542SBram Moolenaar 	{
22308a7d6542SBram Moolenaar 	    case ISN_EXEC:
22318a7d6542SBram Moolenaar 		smsg("%4d EXEC %s", current, iptr->isn_arg.string);
22328a7d6542SBram Moolenaar 		break;
2233cfe435d7SBram Moolenaar 	    case ISN_EXECCONCAT:
2234cfe435d7SBram Moolenaar 		smsg("%4d EXECCONCAT %lld", current,
2235cfe435d7SBram Moolenaar 					      (long long)iptr->isn_arg.number);
2236cfe435d7SBram Moolenaar 		break;
22378a7d6542SBram Moolenaar 	    case ISN_ECHO:
22388a7d6542SBram Moolenaar 		{
22398a7d6542SBram Moolenaar 		    echo_T *echo = &iptr->isn_arg.echo;
22408a7d6542SBram Moolenaar 
22418a7d6542SBram Moolenaar 		    smsg("%4d %s %d", current,
22428a7d6542SBram Moolenaar 			    echo->echo_with_white ? "ECHO" : "ECHON",
22438a7d6542SBram Moolenaar 			    echo->echo_count);
22448a7d6542SBram Moolenaar 		}
22458a7d6542SBram Moolenaar 		break;
2246ad39c094SBram Moolenaar 	    case ISN_EXECUTE:
22471082772fSBram Moolenaar 		smsg("%4d EXECUTE %lld", current,
22481082772fSBram Moolenaar 					    (long long)(iptr->isn_arg.number));
2249ad39c094SBram Moolenaar 		break;
2250f93c7feaSBram Moolenaar 	    case ISN_ECHOMSG:
2251f93c7feaSBram Moolenaar 		smsg("%4d ECHOMSG %lld", current,
2252f93c7feaSBram Moolenaar 					    (long long)(iptr->isn_arg.number));
2253f93c7feaSBram Moolenaar 		break;
2254f93c7feaSBram Moolenaar 	    case ISN_ECHOERR:
2255f93c7feaSBram Moolenaar 		smsg("%4d ECHOERR %lld", current,
2256f93c7feaSBram Moolenaar 					    (long long)(iptr->isn_arg.number));
2257f93c7feaSBram Moolenaar 		break;
22588a7d6542SBram Moolenaar 	    case ISN_LOAD:
2259c8cd2b34SBram Moolenaar 	    case ISN_LOADOUTER:
2260c8cd2b34SBram Moolenaar 		{
2261c8cd2b34SBram Moolenaar 		    char *add = iptr->isn_type == ISN_LOAD ? "" : "OUTER";
2262c8cd2b34SBram Moolenaar 
22638a7d6542SBram Moolenaar 		    if (iptr->isn_arg.number < 0)
2264c8cd2b34SBram Moolenaar 			smsg("%4d LOAD%s arg[%lld]", current, add,
2265c8cd2b34SBram Moolenaar 				(long long)(iptr->isn_arg.number
2266c8cd2b34SBram Moolenaar 							  + STACK_FRAME_SIZE));
22678a7d6542SBram Moolenaar 		    else
2268c8cd2b34SBram Moolenaar 			smsg("%4d LOAD%s $%lld", current, add,
22691082772fSBram Moolenaar 					    (long long)(iptr->isn_arg.number));
2270c8cd2b34SBram Moolenaar 		}
22718a7d6542SBram Moolenaar 		break;
22728a7d6542SBram Moolenaar 	    case ISN_LOADV:
22738a7d6542SBram Moolenaar 		smsg("%4d LOADV v:%s", current,
22748a7d6542SBram Moolenaar 				       get_vim_var_name(iptr->isn_arg.number));
22758a7d6542SBram Moolenaar 		break;
22768a7d6542SBram Moolenaar 	    case ISN_LOADSCRIPT:
22778a7d6542SBram Moolenaar 		{
22788a7d6542SBram Moolenaar 		    scriptitem_T *si =
227921b9e977SBram Moolenaar 				  SCRIPT_ITEM(iptr->isn_arg.script.script_sid);
22808a7d6542SBram Moolenaar 		    svar_T *sv = ((svar_T *)si->sn_var_vals.ga_data)
22818a7d6542SBram Moolenaar 					     + iptr->isn_arg.script.script_idx;
22828a7d6542SBram Moolenaar 
22838a7d6542SBram Moolenaar 		    smsg("%4d LOADSCRIPT %s from %s", current,
22848a7d6542SBram Moolenaar 						     sv->sv_name, si->sn_name);
22858a7d6542SBram Moolenaar 		}
22868a7d6542SBram Moolenaar 		break;
22878a7d6542SBram Moolenaar 	    case ISN_LOADS:
22888a7d6542SBram Moolenaar 		{
2289b283a8a6SBram Moolenaar 		    scriptitem_T *si = SCRIPT_ITEM(
2290b283a8a6SBram Moolenaar 					       iptr->isn_arg.loadstore.ls_sid);
22918a7d6542SBram Moolenaar 
22928a7d6542SBram Moolenaar 		    smsg("%4d LOADS s:%s from %s", current,
22935deeb3f1SBram Moolenaar 				 iptr->isn_arg.loadstore.ls_name, si->sn_name);
22948a7d6542SBram Moolenaar 		}
22958a7d6542SBram Moolenaar 		break;
22968a7d6542SBram Moolenaar 	    case ISN_LOADG:
22978a7d6542SBram Moolenaar 		smsg("%4d LOADG g:%s", current, iptr->isn_arg.string);
22988a7d6542SBram Moolenaar 		break;
2299d3aac291SBram Moolenaar 	    case ISN_LOADB:
2300d3aac291SBram Moolenaar 		smsg("%4d LOADB b:%s", current, iptr->isn_arg.string);
2301d3aac291SBram Moolenaar 		break;
2302d3aac291SBram Moolenaar 	    case ISN_LOADW:
2303d3aac291SBram Moolenaar 		smsg("%4d LOADW w:%s", current, iptr->isn_arg.string);
2304d3aac291SBram Moolenaar 		break;
2305d3aac291SBram Moolenaar 	    case ISN_LOADT:
2306d3aac291SBram Moolenaar 		smsg("%4d LOADT t:%s", current, iptr->isn_arg.string);
2307d3aac291SBram Moolenaar 		break;
23088a7d6542SBram Moolenaar 	    case ISN_LOADOPT:
23098a7d6542SBram Moolenaar 		smsg("%4d LOADOPT %s", current, iptr->isn_arg.string);
23108a7d6542SBram Moolenaar 		break;
23118a7d6542SBram Moolenaar 	    case ISN_LOADENV:
23128a7d6542SBram Moolenaar 		smsg("%4d LOADENV %s", current, iptr->isn_arg.string);
23138a7d6542SBram Moolenaar 		break;
23148a7d6542SBram Moolenaar 	    case ISN_LOADREG:
23151082772fSBram Moolenaar 		smsg("%4d LOADREG @%c", current, (int)(iptr->isn_arg.number));
23168a7d6542SBram Moolenaar 		break;
23178a7d6542SBram Moolenaar 
23188a7d6542SBram Moolenaar 	    case ISN_STORE:
2319b68b346eSBram Moolenaar 	    case ISN_STOREOUTER:
2320b68b346eSBram Moolenaar 		{
2321b68b346eSBram Moolenaar 		    char *add = iptr->isn_type == ISN_STORE ? "" : "OUTER";
2322b68b346eSBram Moolenaar 
2323170fcfcfSBram Moolenaar 		if (iptr->isn_arg.number < 0)
2324b68b346eSBram Moolenaar 		    smsg("%4d STORE%s arg[%lld]", current, add,
2325db99f9f2SBram Moolenaar 			 (long long)(iptr->isn_arg.number + STACK_FRAME_SIZE));
2326170fcfcfSBram Moolenaar 		else
2327b68b346eSBram Moolenaar 		    smsg("%4d STORE%s $%lld", current, add,
23281082772fSBram Moolenaar 					    (long long)(iptr->isn_arg.number));
2329b68b346eSBram Moolenaar 		}
23308a7d6542SBram Moolenaar 		break;
2331b283a8a6SBram Moolenaar 	    case ISN_STOREV:
2332b283a8a6SBram Moolenaar 		smsg("%4d STOREV v:%s", current,
2333b283a8a6SBram Moolenaar 				       get_vim_var_name(iptr->isn_arg.number));
2334b283a8a6SBram Moolenaar 		break;
23358a7d6542SBram Moolenaar 	    case ISN_STOREG:
2336b283a8a6SBram Moolenaar 		smsg("%4d STOREG %s", current, iptr->isn_arg.string);
2337b283a8a6SBram Moolenaar 		break;
2338d3aac291SBram Moolenaar 	    case ISN_STOREB:
2339d3aac291SBram Moolenaar 		smsg("%4d STOREB %s", current, iptr->isn_arg.string);
2340d3aac291SBram Moolenaar 		break;
2341d3aac291SBram Moolenaar 	    case ISN_STOREW:
2342d3aac291SBram Moolenaar 		smsg("%4d STOREW %s", current, iptr->isn_arg.string);
2343d3aac291SBram Moolenaar 		break;
2344d3aac291SBram Moolenaar 	    case ISN_STORET:
2345d3aac291SBram Moolenaar 		smsg("%4d STORET %s", current, iptr->isn_arg.string);
2346d3aac291SBram Moolenaar 		break;
2347b283a8a6SBram Moolenaar 	    case ISN_STORES:
2348b283a8a6SBram Moolenaar 		{
2349b283a8a6SBram Moolenaar 		    scriptitem_T *si = SCRIPT_ITEM(
2350b283a8a6SBram Moolenaar 					       iptr->isn_arg.loadstore.ls_sid);
2351b283a8a6SBram Moolenaar 
23520bbf722aSBram Moolenaar 		    smsg("%4d STORES %s in %s", current,
23535deeb3f1SBram Moolenaar 				 iptr->isn_arg.loadstore.ls_name, si->sn_name);
2354b283a8a6SBram Moolenaar 		}
23558a7d6542SBram Moolenaar 		break;
23568a7d6542SBram Moolenaar 	    case ISN_STORESCRIPT:
23578a7d6542SBram Moolenaar 		{
23588a7d6542SBram Moolenaar 		    scriptitem_T *si =
235921b9e977SBram Moolenaar 				  SCRIPT_ITEM(iptr->isn_arg.script.script_sid);
23608a7d6542SBram Moolenaar 		    svar_T *sv = ((svar_T *)si->sn_var_vals.ga_data)
23618a7d6542SBram Moolenaar 					     + iptr->isn_arg.script.script_idx;
23628a7d6542SBram Moolenaar 
23638a7d6542SBram Moolenaar 		    smsg("%4d STORESCRIPT %s in %s", current,
23648a7d6542SBram Moolenaar 						     sv->sv_name, si->sn_name);
23658a7d6542SBram Moolenaar 		}
23668a7d6542SBram Moolenaar 		break;
23678a7d6542SBram Moolenaar 	    case ISN_STOREOPT:
23688a7d6542SBram Moolenaar 		smsg("%4d STOREOPT &%s", current,
23698a7d6542SBram Moolenaar 					       iptr->isn_arg.storeopt.so_name);
23708a7d6542SBram Moolenaar 		break;
2371b283a8a6SBram Moolenaar 	    case ISN_STOREENV:
2372b283a8a6SBram Moolenaar 		smsg("%4d STOREENV $%s", current, iptr->isn_arg.string);
2373b283a8a6SBram Moolenaar 		break;
2374b283a8a6SBram Moolenaar 	    case ISN_STOREREG:
23751082772fSBram Moolenaar 		smsg("%4d STOREREG @%c", current, (int)iptr->isn_arg.number);
2376b283a8a6SBram Moolenaar 		break;
23778a7d6542SBram Moolenaar 	    case ISN_STORENR:
23788a7d6542SBram Moolenaar 		smsg("%4d STORE %lld in $%d", current,
2379a471eeaeSBram Moolenaar 				iptr->isn_arg.storenr.stnr_val,
2380a471eeaeSBram Moolenaar 				iptr->isn_arg.storenr.stnr_idx);
23818a7d6542SBram Moolenaar 		break;
23828a7d6542SBram Moolenaar 
23838a7d6542SBram Moolenaar 	    // constants
23848a7d6542SBram Moolenaar 	    case ISN_PUSHNR:
23851082772fSBram Moolenaar 		smsg("%4d PUSHNR %lld", current,
23861082772fSBram Moolenaar 					    (long long)(iptr->isn_arg.number));
23878a7d6542SBram Moolenaar 		break;
23888a7d6542SBram Moolenaar 	    case ISN_PUSHBOOL:
23898a7d6542SBram Moolenaar 	    case ISN_PUSHSPEC:
23908a7d6542SBram Moolenaar 		smsg("%4d PUSH %s", current,
23918a7d6542SBram Moolenaar 				   get_var_special_name(iptr->isn_arg.number));
23928a7d6542SBram Moolenaar 		break;
23938a7d6542SBram Moolenaar 	    case ISN_PUSHF:
2394a5d5953dSBram Moolenaar #ifdef FEAT_FLOAT
23958a7d6542SBram Moolenaar 		smsg("%4d PUSHF %g", current, iptr->isn_arg.fnumber);
2396a5d5953dSBram Moolenaar #endif
23978a7d6542SBram Moolenaar 		break;
23988a7d6542SBram Moolenaar 	    case ISN_PUSHS:
23998a7d6542SBram Moolenaar 		smsg("%4d PUSHS \"%s\"", current, iptr->isn_arg.string);
24008a7d6542SBram Moolenaar 		break;
24018a7d6542SBram Moolenaar 	    case ISN_PUSHBLOB:
24028a7d6542SBram Moolenaar 		{
24038a7d6542SBram Moolenaar 		    char_u	*r;
24048a7d6542SBram Moolenaar 		    char_u	numbuf[NUMBUFLEN];
24058a7d6542SBram Moolenaar 		    char_u	*tofree;
24068a7d6542SBram Moolenaar 
24078a7d6542SBram Moolenaar 		    r = blob2string(iptr->isn_arg.blob, &tofree, numbuf);
2408ff80cb68SBram Moolenaar 		    smsg("%4d PUSHBLOB %s", current, r);
24098a7d6542SBram Moolenaar 		    vim_free(tofree);
24108a7d6542SBram Moolenaar 		}
24118a7d6542SBram Moolenaar 		break;
241242a480bfSBram Moolenaar 	    case ISN_PUSHFUNC:
2413087d2e15SBram Moolenaar 		{
2414087d2e15SBram Moolenaar 		    char *name = (char *)iptr->isn_arg.string;
2415087d2e15SBram Moolenaar 
2416087d2e15SBram Moolenaar 		    smsg("%4d PUSHFUNC \"%s\"", current,
2417087d2e15SBram Moolenaar 					       name == NULL ? "[none]" : name);
2418087d2e15SBram Moolenaar 		}
241942a480bfSBram Moolenaar 		break;
242042a480bfSBram Moolenaar 	    case ISN_PUSHCHANNEL:
242142a480bfSBram Moolenaar #ifdef FEAT_JOB_CHANNEL
242242a480bfSBram Moolenaar 		{
242342a480bfSBram Moolenaar 		    channel_T *channel = iptr->isn_arg.channel;
242442a480bfSBram Moolenaar 
242542a480bfSBram Moolenaar 		    smsg("%4d PUSHCHANNEL %d", current,
242642a480bfSBram Moolenaar 					 channel == NULL ? 0 : channel->ch_id);
242742a480bfSBram Moolenaar 		}
242842a480bfSBram Moolenaar #endif
242942a480bfSBram Moolenaar 		break;
243042a480bfSBram Moolenaar 	    case ISN_PUSHJOB:
243142a480bfSBram Moolenaar #ifdef FEAT_JOB_CHANNEL
243242a480bfSBram Moolenaar 		{
243342a480bfSBram Moolenaar 		    typval_T	tv;
243442a480bfSBram Moolenaar 		    char_u	*name;
243542a480bfSBram Moolenaar 
243642a480bfSBram Moolenaar 		    tv.v_type = VAR_JOB;
243742a480bfSBram Moolenaar 		    tv.vval.v_job = iptr->isn_arg.job;
243842a480bfSBram Moolenaar 		    name = tv_get_string(&tv);
2439f51cb4e0SBram Moolenaar 		    smsg("%4d PUSHJOB \"%s\"", current, name);
244042a480bfSBram Moolenaar 		}
244142a480bfSBram Moolenaar #endif
244242a480bfSBram Moolenaar 		break;
24438a7d6542SBram Moolenaar 	    case ISN_PUSHEXC:
24448a7d6542SBram Moolenaar 		smsg("%4d PUSH v:exception", current);
24458a7d6542SBram Moolenaar 		break;
2446d72c1bf0SBram Moolenaar 	    case ISN_UNLET:
2447d72c1bf0SBram Moolenaar 		smsg("%4d UNLET%s %s", current,
2448d72c1bf0SBram Moolenaar 			iptr->isn_arg.unlet.ul_forceit ? "!" : "",
2449d72c1bf0SBram Moolenaar 			iptr->isn_arg.unlet.ul_name);
2450d72c1bf0SBram Moolenaar 		break;
24517bdaea6eSBram Moolenaar 	    case ISN_UNLETENV:
24527bdaea6eSBram Moolenaar 		smsg("%4d UNLETENV%s $%s", current,
24537bdaea6eSBram Moolenaar 			iptr->isn_arg.unlet.ul_forceit ? "!" : "",
24547bdaea6eSBram Moolenaar 			iptr->isn_arg.unlet.ul_name);
24557bdaea6eSBram Moolenaar 		break;
24568a7d6542SBram Moolenaar 	    case ISN_NEWLIST:
24571082772fSBram Moolenaar 		smsg("%4d NEWLIST size %lld", current,
24581082772fSBram Moolenaar 					    (long long)(iptr->isn_arg.number));
24598a7d6542SBram Moolenaar 		break;
24608a7d6542SBram Moolenaar 	    case ISN_NEWDICT:
24611082772fSBram Moolenaar 		smsg("%4d NEWDICT size %lld", current,
24621082772fSBram Moolenaar 					    (long long)(iptr->isn_arg.number));
24638a7d6542SBram Moolenaar 		break;
24648a7d6542SBram Moolenaar 
24658a7d6542SBram Moolenaar 	    // function call
24668a7d6542SBram Moolenaar 	    case ISN_BCALL:
24678a7d6542SBram Moolenaar 		{
24688a7d6542SBram Moolenaar 		    cbfunc_T	*cbfunc = &iptr->isn_arg.bfunc;
24698a7d6542SBram Moolenaar 
24708a7d6542SBram Moolenaar 		    smsg("%4d BCALL %s(argc %d)", current,
24718a7d6542SBram Moolenaar 			    internal_func_name(cbfunc->cbf_idx),
24728a7d6542SBram Moolenaar 			    cbfunc->cbf_argcount);
24738a7d6542SBram Moolenaar 		}
24748a7d6542SBram Moolenaar 		break;
24758a7d6542SBram Moolenaar 	    case ISN_DCALL:
24768a7d6542SBram Moolenaar 		{
24778a7d6542SBram Moolenaar 		    cdfunc_T	*cdfunc = &iptr->isn_arg.dfunc;
24788a7d6542SBram Moolenaar 		    dfunc_T	*df = ((dfunc_T *)def_functions.ga_data)
24798a7d6542SBram Moolenaar 							     + cdfunc->cdf_idx;
24808a7d6542SBram Moolenaar 
24818a7d6542SBram Moolenaar 		    smsg("%4d DCALL %s(argc %d)", current,
24828a7d6542SBram Moolenaar 			    df->df_ufunc->uf_name_exp != NULL
24838a7d6542SBram Moolenaar 				? df->df_ufunc->uf_name_exp
24848a7d6542SBram Moolenaar 				: df->df_ufunc->uf_name, cdfunc->cdf_argcount);
24858a7d6542SBram Moolenaar 		}
24868a7d6542SBram Moolenaar 		break;
24878a7d6542SBram Moolenaar 	    case ISN_UCALL:
24888a7d6542SBram Moolenaar 		{
24898a7d6542SBram Moolenaar 		    cufunc_T	*cufunc = &iptr->isn_arg.ufunc;
24908a7d6542SBram Moolenaar 
24918a7d6542SBram Moolenaar 		    smsg("%4d UCALL %s(argc %d)", current,
24928a7d6542SBram Moolenaar 				       cufunc->cuf_name, cufunc->cuf_argcount);
24938a7d6542SBram Moolenaar 		}
24948a7d6542SBram Moolenaar 		break;
24958a7d6542SBram Moolenaar 	    case ISN_PCALL:
24968a7d6542SBram Moolenaar 		{
24978a7d6542SBram Moolenaar 		    cpfunc_T	*cpfunc = &iptr->isn_arg.pfunc;
24988a7d6542SBram Moolenaar 
24998a7d6542SBram Moolenaar 		    smsg("%4d PCALL%s (argc %d)", current,
25008a7d6542SBram Moolenaar 			   cpfunc->cpf_top ? " top" : "", cpfunc->cpf_argcount);
25018a7d6542SBram Moolenaar 		}
25028a7d6542SBram Moolenaar 		break;
2503bd5da371SBram Moolenaar 	    case ISN_PCALL_END:
2504bd5da371SBram Moolenaar 		smsg("%4d PCALL end", current);
2505bd5da371SBram Moolenaar 		break;
25068a7d6542SBram Moolenaar 	    case ISN_RETURN:
25078a7d6542SBram Moolenaar 		smsg("%4d RETURN", current);
25088a7d6542SBram Moolenaar 		break;
25098a7d6542SBram Moolenaar 	    case ISN_FUNCREF:
25108a7d6542SBram Moolenaar 		{
25115adc55cbSBram Moolenaar 		    funcref_T	*funcref = &iptr->isn_arg.funcref;
25128a7d6542SBram Moolenaar 		    dfunc_T	*df = ((dfunc_T *)def_functions.ga_data)
25135adc55cbSBram Moolenaar 							    + funcref->fr_func;
25148a7d6542SBram Moolenaar 
2515bf67ea1aSBram Moolenaar 		    smsg("%4d FUNCREF %s $%d", current, df->df_ufunc->uf_name,
25165adc55cbSBram Moolenaar 				     funcref->fr_var_idx + dfunc->df_varcount);
25178a7d6542SBram Moolenaar 		}
25188a7d6542SBram Moolenaar 		break;
25198a7d6542SBram Moolenaar 
25208a7d6542SBram Moolenaar 	    case ISN_JUMP:
25218a7d6542SBram Moolenaar 		{
25228a7d6542SBram Moolenaar 		    char *when = "?";
25238a7d6542SBram Moolenaar 
25248a7d6542SBram Moolenaar 		    switch (iptr->isn_arg.jump.jump_when)
25258a7d6542SBram Moolenaar 		    {
25268a7d6542SBram Moolenaar 			case JUMP_ALWAYS:
25278a7d6542SBram Moolenaar 			    when = "JUMP";
25288a7d6542SBram Moolenaar 			    break;
25298a7d6542SBram Moolenaar 			case JUMP_AND_KEEP_IF_TRUE:
25308a7d6542SBram Moolenaar 			    when = "JUMP_AND_KEEP_IF_TRUE";
25318a7d6542SBram Moolenaar 			    break;
25328a7d6542SBram Moolenaar 			case JUMP_IF_FALSE:
25338a7d6542SBram Moolenaar 			    when = "JUMP_IF_FALSE";
25348a7d6542SBram Moolenaar 			    break;
25358a7d6542SBram Moolenaar 			case JUMP_AND_KEEP_IF_FALSE:
25368a7d6542SBram Moolenaar 			    when = "JUMP_AND_KEEP_IF_FALSE";
25378a7d6542SBram Moolenaar 			    break;
25388a7d6542SBram Moolenaar 		    }
25398a677a37SBram Moolenaar 		    smsg("%4d %s -> %d", current, when,
25408a7d6542SBram Moolenaar 						iptr->isn_arg.jump.jump_where);
25418a7d6542SBram Moolenaar 		}
25428a7d6542SBram Moolenaar 		break;
25438a7d6542SBram Moolenaar 
25448a7d6542SBram Moolenaar 	    case ISN_FOR:
25458a7d6542SBram Moolenaar 		{
25468a7d6542SBram Moolenaar 		    forloop_T *forloop = &iptr->isn_arg.forloop;
25478a7d6542SBram Moolenaar 
25488a7d6542SBram Moolenaar 		    smsg("%4d FOR $%d -> %d", current,
25498a7d6542SBram Moolenaar 					   forloop->for_idx, forloop->for_end);
25508a7d6542SBram Moolenaar 		}
25518a7d6542SBram Moolenaar 		break;
25528a7d6542SBram Moolenaar 
25538a7d6542SBram Moolenaar 	    case ISN_TRY:
25548a7d6542SBram Moolenaar 		{
25558a7d6542SBram Moolenaar 		    try_T *try = &iptr->isn_arg.try;
25568a7d6542SBram Moolenaar 
25578a7d6542SBram Moolenaar 		    smsg("%4d TRY catch -> %d, finally -> %d", current,
25588a7d6542SBram Moolenaar 					     try->try_catch, try->try_finally);
25598a7d6542SBram Moolenaar 		}
25608a7d6542SBram Moolenaar 		break;
25618a7d6542SBram Moolenaar 	    case ISN_CATCH:
25628a7d6542SBram Moolenaar 		// TODO
25638a7d6542SBram Moolenaar 		smsg("%4d CATCH", current);
25648a7d6542SBram Moolenaar 		break;
25658a7d6542SBram Moolenaar 	    case ISN_ENDTRY:
25668a7d6542SBram Moolenaar 		smsg("%4d ENDTRY", current);
25678a7d6542SBram Moolenaar 		break;
25688a7d6542SBram Moolenaar 	    case ISN_THROW:
25698a7d6542SBram Moolenaar 		smsg("%4d THROW", current);
25708a7d6542SBram Moolenaar 		break;
25718a7d6542SBram Moolenaar 
25728a7d6542SBram Moolenaar 	    // expression operations on number
25738a7d6542SBram Moolenaar 	    case ISN_OPNR:
25748a7d6542SBram Moolenaar 	    case ISN_OPFLOAT:
25758a7d6542SBram Moolenaar 	    case ISN_OPANY:
25768a7d6542SBram Moolenaar 		{
25778a7d6542SBram Moolenaar 		    char *what;
25788a7d6542SBram Moolenaar 		    char *ins;
25798a7d6542SBram Moolenaar 
25808a7d6542SBram Moolenaar 		    switch (iptr->isn_arg.op.op_type)
25818a7d6542SBram Moolenaar 		    {
25828a7d6542SBram Moolenaar 			case EXPR_MULT: what = "*"; break;
25838a7d6542SBram Moolenaar 			case EXPR_DIV: what = "/"; break;
25848a7d6542SBram Moolenaar 			case EXPR_REM: what = "%"; break;
25858a7d6542SBram Moolenaar 			case EXPR_SUB: what = "-"; break;
25868a7d6542SBram Moolenaar 			case EXPR_ADD: what = "+"; break;
25878a7d6542SBram Moolenaar 			default:       what = "???"; break;
25888a7d6542SBram Moolenaar 		    }
25898a7d6542SBram Moolenaar 		    switch (iptr->isn_type)
25908a7d6542SBram Moolenaar 		    {
25918a7d6542SBram Moolenaar 			case ISN_OPNR: ins = "OPNR"; break;
25928a7d6542SBram Moolenaar 			case ISN_OPFLOAT: ins = "OPFLOAT"; break;
25938a7d6542SBram Moolenaar 			case ISN_OPANY: ins = "OPANY"; break;
25948a7d6542SBram Moolenaar 			default: ins = "???"; break;
25958a7d6542SBram Moolenaar 		    }
25968a7d6542SBram Moolenaar 		    smsg("%4d %s %s", current, ins, what);
25978a7d6542SBram Moolenaar 		}
25988a7d6542SBram Moolenaar 		break;
25998a7d6542SBram Moolenaar 
26008a7d6542SBram Moolenaar 	    case ISN_COMPAREBOOL:
26018a7d6542SBram Moolenaar 	    case ISN_COMPARESPECIAL:
26028a7d6542SBram Moolenaar 	    case ISN_COMPARENR:
26038a7d6542SBram Moolenaar 	    case ISN_COMPAREFLOAT:
26048a7d6542SBram Moolenaar 	    case ISN_COMPARESTRING:
26058a7d6542SBram Moolenaar 	    case ISN_COMPAREBLOB:
26068a7d6542SBram Moolenaar 	    case ISN_COMPARELIST:
26078a7d6542SBram Moolenaar 	    case ISN_COMPAREDICT:
26088a7d6542SBram Moolenaar 	    case ISN_COMPAREFUNC:
26098a7d6542SBram Moolenaar 	    case ISN_COMPAREANY:
26108a7d6542SBram Moolenaar 		   {
26118a7d6542SBram Moolenaar 		       char *p;
26128a7d6542SBram Moolenaar 		       char buf[10];
26138a7d6542SBram Moolenaar 		       char *type;
26148a7d6542SBram Moolenaar 
26158a7d6542SBram Moolenaar 		       switch (iptr->isn_arg.op.op_type)
26168a7d6542SBram Moolenaar 		       {
26178a7d6542SBram Moolenaar 			   case EXPR_EQUAL:	 p = "=="; break;
26188a7d6542SBram Moolenaar 			   case EXPR_NEQUAL:    p = "!="; break;
26198a7d6542SBram Moolenaar 			   case EXPR_GREATER:   p = ">"; break;
26208a7d6542SBram Moolenaar 			   case EXPR_GEQUAL:    p = ">="; break;
26218a7d6542SBram Moolenaar 			   case EXPR_SMALLER:   p = "<"; break;
26228a7d6542SBram Moolenaar 			   case EXPR_SEQUAL:    p = "<="; break;
26238a7d6542SBram Moolenaar 			   case EXPR_MATCH:	 p = "=~"; break;
26248a7d6542SBram Moolenaar 			   case EXPR_IS:	 p = "is"; break;
26258a7d6542SBram Moolenaar 			   case EXPR_ISNOT:	 p = "isnot"; break;
26268a7d6542SBram Moolenaar 			   case EXPR_NOMATCH:	 p = "!~"; break;
26278a7d6542SBram Moolenaar 			   default:  p = "???"; break;
26288a7d6542SBram Moolenaar 		       }
26298a7d6542SBram Moolenaar 		       STRCPY(buf, p);
26308a7d6542SBram Moolenaar 		       if (iptr->isn_arg.op.op_ic == TRUE)
26318a7d6542SBram Moolenaar 			   strcat(buf, "?");
26328a7d6542SBram Moolenaar 		       switch(iptr->isn_type)
26338a7d6542SBram Moolenaar 		       {
26348a7d6542SBram Moolenaar 			   case ISN_COMPAREBOOL: type = "COMPAREBOOL"; break;
26358a7d6542SBram Moolenaar 			   case ISN_COMPARESPECIAL:
26368a7d6542SBram Moolenaar 						 type = "COMPARESPECIAL"; break;
26378a7d6542SBram Moolenaar 			   case ISN_COMPARENR: type = "COMPARENR"; break;
26388a7d6542SBram Moolenaar 			   case ISN_COMPAREFLOAT: type = "COMPAREFLOAT"; break;
26398a7d6542SBram Moolenaar 			   case ISN_COMPARESTRING:
26408a7d6542SBram Moolenaar 						  type = "COMPARESTRING"; break;
26418a7d6542SBram Moolenaar 			   case ISN_COMPAREBLOB: type = "COMPAREBLOB"; break;
26428a7d6542SBram Moolenaar 			   case ISN_COMPARELIST: type = "COMPARELIST"; break;
26438a7d6542SBram Moolenaar 			   case ISN_COMPAREDICT: type = "COMPAREDICT"; break;
26448a7d6542SBram Moolenaar 			   case ISN_COMPAREFUNC: type = "COMPAREFUNC"; break;
26458a7d6542SBram Moolenaar 			   case ISN_COMPAREANY: type = "COMPAREANY"; break;
26468a7d6542SBram Moolenaar 			   default: type = "???"; break;
26478a7d6542SBram Moolenaar 		       }
26488a7d6542SBram Moolenaar 
26498a7d6542SBram Moolenaar 		       smsg("%4d %s %s", current, type, buf);
26508a7d6542SBram Moolenaar 		   }
26518a7d6542SBram Moolenaar 		   break;
26528a7d6542SBram Moolenaar 
26538a7d6542SBram Moolenaar 	    case ISN_ADDLIST: smsg("%4d ADDLIST", current); break;
26548a7d6542SBram Moolenaar 	    case ISN_ADDBLOB: smsg("%4d ADDBLOB", current); break;
26558a7d6542SBram Moolenaar 
26568a7d6542SBram Moolenaar 	    // expression operations
26578a7d6542SBram Moolenaar 	    case ISN_CONCAT: smsg("%4d CONCAT", current); break;
26588a7d6542SBram Moolenaar 	    case ISN_INDEX: smsg("%4d INDEX", current); break;
26598a7d6542SBram Moolenaar 	    case ISN_MEMBER: smsg("%4d MEMBER %s", current,
26608a7d6542SBram Moolenaar 						  iptr->isn_arg.string); break;
26618a7d6542SBram Moolenaar 	    case ISN_NEGATENR: smsg("%4d NEGATENR", current); break;
26628a7d6542SBram Moolenaar 
26638a7d6542SBram Moolenaar 	    case ISN_CHECKNR: smsg("%4d CHECKNR", current); break;
26648a7d6542SBram Moolenaar 	    case ISN_CHECKTYPE: smsg("%4d CHECKTYPE %s stack[%d]", current,
26658a7d6542SBram Moolenaar 				      vartype_name(iptr->isn_arg.type.ct_type),
26668a7d6542SBram Moolenaar 				      iptr->isn_arg.type.ct_off);
26678a7d6542SBram Moolenaar 				break;
26688a7d6542SBram Moolenaar 	    case ISN_2BOOL: if (iptr->isn_arg.number)
26698a7d6542SBram Moolenaar 				smsg("%4d INVERT (!val)", current);
26708a7d6542SBram Moolenaar 			    else
26718a7d6542SBram Moolenaar 				smsg("%4d 2BOOL (!!val)", current);
26728a7d6542SBram Moolenaar 			    break;
2673db99f9f2SBram Moolenaar 	    case ISN_2STRING: smsg("%4d 2STRING stack[%lld]", current,
2674db99f9f2SBram Moolenaar 					 (long long)(iptr->isn_arg.number));
26758a7d6542SBram Moolenaar 				break;
26768a7d6542SBram Moolenaar 
26778a7d6542SBram Moolenaar 	    case ISN_DROP: smsg("%4d DROP", current); break;
26788a7d6542SBram Moolenaar 	}
26798a7d6542SBram Moolenaar     }
26808a7d6542SBram Moolenaar }
26818a7d6542SBram Moolenaar 
26828a7d6542SBram Moolenaar /*
26838a7d6542SBram Moolenaar  * Return TRUE when "tv" is not falsey: non-zero, non-empty string, non-empty
26848a7d6542SBram Moolenaar  * list, etc.  Mostly like what JavaScript does, except that empty list and
26858a7d6542SBram Moolenaar  * empty dictionary are FALSE.
26868a7d6542SBram Moolenaar  */
26878a7d6542SBram Moolenaar     int
26888a7d6542SBram Moolenaar tv2bool(typval_T *tv)
26898a7d6542SBram Moolenaar {
26908a7d6542SBram Moolenaar     switch (tv->v_type)
26918a7d6542SBram Moolenaar     {
26928a7d6542SBram Moolenaar 	case VAR_NUMBER:
26938a7d6542SBram Moolenaar 	    return tv->vval.v_number != 0;
26948a7d6542SBram Moolenaar 	case VAR_FLOAT:
26958a7d6542SBram Moolenaar #ifdef FEAT_FLOAT
26968a7d6542SBram Moolenaar 	    return tv->vval.v_float != 0.0;
26978a7d6542SBram Moolenaar #else
26988a7d6542SBram Moolenaar 	    break;
26998a7d6542SBram Moolenaar #endif
27008a7d6542SBram Moolenaar 	case VAR_PARTIAL:
27018a7d6542SBram Moolenaar 	    return tv->vval.v_partial != NULL;
27028a7d6542SBram Moolenaar 	case VAR_FUNC:
27038a7d6542SBram Moolenaar 	case VAR_STRING:
27048a7d6542SBram Moolenaar 	    return tv->vval.v_string != NULL && *tv->vval.v_string != NUL;
27058a7d6542SBram Moolenaar 	case VAR_LIST:
27068a7d6542SBram Moolenaar 	    return tv->vval.v_list != NULL && tv->vval.v_list->lv_len > 0;
27078a7d6542SBram Moolenaar 	case VAR_DICT:
27088a7d6542SBram Moolenaar 	    return tv->vval.v_dict != NULL
27098a7d6542SBram Moolenaar 				    && tv->vval.v_dict->dv_hashtab.ht_used > 0;
27108a7d6542SBram Moolenaar 	case VAR_BOOL:
27118a7d6542SBram Moolenaar 	case VAR_SPECIAL:
27128a7d6542SBram Moolenaar 	    return tv->vval.v_number == VVAL_TRUE ? TRUE : FALSE;
27138a7d6542SBram Moolenaar 	case VAR_JOB:
27148a7d6542SBram Moolenaar #ifdef FEAT_JOB_CHANNEL
27158a7d6542SBram Moolenaar 	    return tv->vval.v_job != NULL;
27168a7d6542SBram Moolenaar #else
27178a7d6542SBram Moolenaar 	    break;
27188a7d6542SBram Moolenaar #endif
27198a7d6542SBram Moolenaar 	case VAR_CHANNEL:
27208a7d6542SBram Moolenaar #ifdef FEAT_JOB_CHANNEL
27218a7d6542SBram Moolenaar 	    return tv->vval.v_channel != NULL;
27228a7d6542SBram Moolenaar #else
27238a7d6542SBram Moolenaar 	    break;
27248a7d6542SBram Moolenaar #endif
27258a7d6542SBram Moolenaar 	case VAR_BLOB:
27268a7d6542SBram Moolenaar 	    return tv->vval.v_blob != NULL && tv->vval.v_blob->bv_ga.ga_len > 0;
27278a7d6542SBram Moolenaar 	case VAR_UNKNOWN:
27284c683750SBram Moolenaar 	case VAR_ANY:
27298a7d6542SBram Moolenaar 	case VAR_VOID:
27308a7d6542SBram Moolenaar 	    break;
27318a7d6542SBram Moolenaar     }
27328a7d6542SBram Moolenaar     return FALSE;
27338a7d6542SBram Moolenaar }
27348a7d6542SBram Moolenaar 
27358a7d6542SBram Moolenaar /*
27368a7d6542SBram Moolenaar  * If "tv" is a string give an error and return FAIL.
27378a7d6542SBram Moolenaar  */
27388a7d6542SBram Moolenaar     int
27398a7d6542SBram Moolenaar check_not_string(typval_T *tv)
27408a7d6542SBram Moolenaar {
27418a7d6542SBram Moolenaar     if (tv->v_type == VAR_STRING)
27428a7d6542SBram Moolenaar     {
27438a7d6542SBram Moolenaar 	emsg(_("E1030: Using a String as a Number"));
27448a7d6542SBram Moolenaar 	clear_tv(tv);
27458a7d6542SBram Moolenaar 	return FAIL;
27468a7d6542SBram Moolenaar     }
27478a7d6542SBram Moolenaar     return OK;
27488a7d6542SBram Moolenaar }
27498a7d6542SBram Moolenaar 
27508a7d6542SBram Moolenaar 
27518a7d6542SBram Moolenaar #endif // FEAT_EVAL
2752