xref: /vim-8.2.3635/src/vim9execute.c (revision d5aec0ce)
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 {
278a7d6542SBram Moolenaar     int	    tcd_frame;		// ec_frame 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
598a7d6542SBram Moolenaar     int		ec_frame;	// index in ec_stack: context of ec_dfunc_idx
608a7d6542SBram Moolenaar 
618a7d6542SBram Moolenaar     garray_T	ec_trystack;	// stack of trycmd_T values
628a7d6542SBram Moolenaar     int		ec_in_catch;	// when TRUE in catch or finally block
638a7d6542SBram Moolenaar 
648a7d6542SBram Moolenaar     int		ec_dfunc_idx;	// current function index
658a7d6542SBram Moolenaar     isn_T	*ec_instr;	// array with instructions
668a7d6542SBram Moolenaar     int		ec_iidx;	// index in ec_instr: instruction to execute
678a7d6542SBram Moolenaar } ectx_T;
688a7d6542SBram Moolenaar 
698a7d6542SBram Moolenaar // Get pointer to item relative to the bottom of the stack, -1 is the last one.
708a7d6542SBram Moolenaar #define STACK_TV_BOT(idx) (((typval_T *)ectx->ec_stack.ga_data) + ectx->ec_stack.ga_len + idx)
718a7d6542SBram Moolenaar 
728a7d6542SBram Moolenaar /*
73170fcfcfSBram Moolenaar  * Return the number of arguments, including optional arguments and any vararg.
748a7d6542SBram Moolenaar  */
758a7d6542SBram Moolenaar     static int
768a7d6542SBram Moolenaar ufunc_argcount(ufunc_T *ufunc)
778a7d6542SBram Moolenaar {
788a7d6542SBram Moolenaar     return ufunc->uf_args.ga_len + (ufunc->uf_va_name != NULL ? 1 : 0);
798a7d6542SBram Moolenaar }
808a7d6542SBram Moolenaar 
818a7d6542SBram Moolenaar /*
82170fcfcfSBram Moolenaar  * Set the instruction index, depending on omitted arguments, where the default
83170fcfcfSBram Moolenaar  * values are to be computed.  If all optional arguments are present, start
84170fcfcfSBram Moolenaar  * with the function body.
85170fcfcfSBram Moolenaar  * The expression evaluation is at the start of the instructions:
86170fcfcfSBram Moolenaar  *  0 ->  EVAL default1
87170fcfcfSBram Moolenaar  *	       STORE arg[-2]
88170fcfcfSBram Moolenaar  *  1 ->  EVAL default2
89170fcfcfSBram Moolenaar  *	       STORE arg[-1]
90170fcfcfSBram Moolenaar  *  2 ->  function body
91170fcfcfSBram Moolenaar  */
92170fcfcfSBram Moolenaar     static void
93170fcfcfSBram Moolenaar init_instr_idx(ufunc_T *ufunc, int argcount, ectx_T *ectx)
94170fcfcfSBram Moolenaar {
95170fcfcfSBram Moolenaar     if (ufunc->uf_def_args.ga_len == 0)
96170fcfcfSBram Moolenaar 	ectx->ec_iidx = 0;
97170fcfcfSBram Moolenaar     else
98170fcfcfSBram Moolenaar     {
99170fcfcfSBram Moolenaar 	int	defcount = ufunc->uf_args.ga_len - argcount;
100170fcfcfSBram Moolenaar 
101170fcfcfSBram Moolenaar 	// If there is a varargs argument defcount can be negative, no defaults
102170fcfcfSBram Moolenaar 	// to evaluate then.
103170fcfcfSBram Moolenaar 	if (defcount < 0)
104170fcfcfSBram Moolenaar 	    defcount = 0;
105170fcfcfSBram Moolenaar 	ectx->ec_iidx = ufunc->uf_def_arg_idx[
106170fcfcfSBram Moolenaar 					 ufunc->uf_def_args.ga_len - defcount];
107170fcfcfSBram Moolenaar     }
108170fcfcfSBram Moolenaar }
109170fcfcfSBram Moolenaar 
110170fcfcfSBram Moolenaar /*
1118a7d6542SBram Moolenaar  * Call compiled function "cdf_idx" from compiled code.
1128a7d6542SBram Moolenaar  *
1138a7d6542SBram Moolenaar  * Stack has:
1148a7d6542SBram Moolenaar  * - current arguments (already there)
1158a7d6542SBram Moolenaar  * - omitted optional argument (default values) added here
1168a7d6542SBram Moolenaar  * - stack frame:
1178a7d6542SBram Moolenaar  *	- pointer to calling function
1188a7d6542SBram Moolenaar  *	- Index of next instruction in calling function
1198a7d6542SBram Moolenaar  *	- previous frame pointer
1208a7d6542SBram Moolenaar  * - reserved space for local variables
1218a7d6542SBram Moolenaar  */
1228a7d6542SBram Moolenaar     static int
1238a7d6542SBram Moolenaar call_dfunc(int cdf_idx, int argcount, ectx_T *ectx)
1248a7d6542SBram Moolenaar {
1258a7d6542SBram Moolenaar     dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data) + cdf_idx;
1268a7d6542SBram Moolenaar     ufunc_T *ufunc = dfunc->df_ufunc;
1278a7d6542SBram Moolenaar     int	    optcount = ufunc_argcount(ufunc) - argcount;
1288a7d6542SBram Moolenaar     int	    idx;
1298a7d6542SBram Moolenaar 
1308a7d6542SBram Moolenaar     if (dfunc->df_deleted)
1318a7d6542SBram Moolenaar     {
1328a7d6542SBram Moolenaar 	emsg_funcname(e_func_deleted, ufunc->uf_name);
1338a7d6542SBram Moolenaar 	return FAIL;
1348a7d6542SBram Moolenaar     }
1358a7d6542SBram Moolenaar 
1368a7d6542SBram Moolenaar     if (ga_grow(&ectx->ec_stack, optcount + 3 + dfunc->df_varcount) == FAIL)
1378a7d6542SBram Moolenaar 	return FAIL;
1388a7d6542SBram Moolenaar 
1398a7d6542SBram Moolenaar     if (optcount < 0)
1408a7d6542SBram Moolenaar     {
1418a7d6542SBram Moolenaar 	emsg("argument count wrong?");
1428a7d6542SBram Moolenaar 	return FAIL;
1438a7d6542SBram Moolenaar     }
144170fcfcfSBram Moolenaar 
145170fcfcfSBram Moolenaar     // Reserve space for omitted optional arguments, filled in soon.
146170fcfcfSBram Moolenaar     // Also any empty varargs argument.
147170fcfcfSBram Moolenaar     ectx->ec_stack.ga_len += optcount;
1488a7d6542SBram Moolenaar 
1498a7d6542SBram Moolenaar     // Store current execution state in stack frame for ISN_RETURN.
1508a7d6542SBram Moolenaar     // TODO: If the actual number of arguments doesn't match what the called
1518a7d6542SBram Moolenaar     // function expects things go bad.
1528a7d6542SBram Moolenaar     STACK_TV_BOT(0)->vval.v_number = ectx->ec_dfunc_idx;
1538a7d6542SBram Moolenaar     STACK_TV_BOT(1)->vval.v_number = ectx->ec_iidx;
1548a7d6542SBram Moolenaar     STACK_TV_BOT(2)->vval.v_number = ectx->ec_frame;
1558a7d6542SBram Moolenaar     ectx->ec_frame = ectx->ec_stack.ga_len;
1568a7d6542SBram Moolenaar 
1578a7d6542SBram Moolenaar     // Initialize local variables
1588a7d6542SBram Moolenaar     for (idx = 0; idx < dfunc->df_varcount; ++idx)
1598a7d6542SBram Moolenaar 	STACK_TV_BOT(STACK_FRAME_SIZE + idx)->v_type = VAR_UNKNOWN;
1608a7d6542SBram Moolenaar     ectx->ec_stack.ga_len += STACK_FRAME_SIZE + dfunc->df_varcount;
1618a7d6542SBram Moolenaar 
1628a7d6542SBram Moolenaar     // Set execution state to the start of the called function.
1638a7d6542SBram Moolenaar     ectx->ec_dfunc_idx = cdf_idx;
1648a7d6542SBram Moolenaar     ectx->ec_instr = dfunc->df_instr;
1658a7d6542SBram Moolenaar     estack_push_ufunc(ETYPE_UFUNC, dfunc->df_ufunc, 1);
166170fcfcfSBram Moolenaar 
167170fcfcfSBram Moolenaar     // Decide where to start execution, handles optional arguments.
168170fcfcfSBram Moolenaar     init_instr_idx(ufunc, argcount, ectx);
1698a7d6542SBram Moolenaar 
1708a7d6542SBram Moolenaar     return OK;
1718a7d6542SBram Moolenaar }
1728a7d6542SBram Moolenaar 
1738a7d6542SBram Moolenaar // Get pointer to item in the stack.
1748a7d6542SBram Moolenaar #define STACK_TV(idx) (((typval_T *)ectx->ec_stack.ga_data) + idx)
1758a7d6542SBram Moolenaar 
1768a7d6542SBram Moolenaar /*
1778a7d6542SBram Moolenaar  * Return from the current function.
1788a7d6542SBram Moolenaar  */
1798a7d6542SBram Moolenaar     static void
1808a7d6542SBram Moolenaar func_return(ectx_T *ectx)
1818a7d6542SBram Moolenaar {
1828a7d6542SBram Moolenaar     int		idx;
1838a7d6542SBram Moolenaar     dfunc_T	*dfunc;
184170fcfcfSBram Moolenaar     int		top;
1858a7d6542SBram Moolenaar 
1868a7d6542SBram Moolenaar     // execution context goes one level up
1878a7d6542SBram Moolenaar     estack_pop();
1888a7d6542SBram Moolenaar 
1898a7d6542SBram Moolenaar     // Clear the local variables and temporary values, but not
1908a7d6542SBram Moolenaar     // the return value.
1918a7d6542SBram Moolenaar     for (idx = ectx->ec_frame + STACK_FRAME_SIZE;
1928a7d6542SBram Moolenaar 					idx < ectx->ec_stack.ga_len - 1; ++idx)
1938a7d6542SBram Moolenaar 	clear_tv(STACK_TV(idx));
194170fcfcfSBram Moolenaar 
195170fcfcfSBram Moolenaar     // Clear the arguments.
1968a7d6542SBram Moolenaar     dfunc = ((dfunc_T *)def_functions.ga_data) + ectx->ec_dfunc_idx;
197170fcfcfSBram Moolenaar     top = ectx->ec_frame - ufunc_argcount(dfunc->df_ufunc);
198170fcfcfSBram Moolenaar     for (idx = top; idx < ectx->ec_frame; ++idx)
199170fcfcfSBram Moolenaar 	clear_tv(STACK_TV(idx));
200170fcfcfSBram Moolenaar 
201170fcfcfSBram Moolenaar     // Restore the previous frame.
2028a7d6542SBram Moolenaar     ectx->ec_dfunc_idx = STACK_TV(ectx->ec_frame)->vval.v_number;
2038a7d6542SBram Moolenaar     ectx->ec_iidx = STACK_TV(ectx->ec_frame + 1)->vval.v_number;
2048a7d6542SBram Moolenaar     ectx->ec_frame = STACK_TV(ectx->ec_frame + 2)->vval.v_number;
2058a7d6542SBram Moolenaar     dfunc = ((dfunc_T *)def_functions.ga_data) + ectx->ec_dfunc_idx;
2068a7d6542SBram Moolenaar     ectx->ec_instr = dfunc->df_instr;
207170fcfcfSBram Moolenaar 
208170fcfcfSBram Moolenaar     // Reset the stack to the position before the call, move the return value
209170fcfcfSBram Moolenaar     // to the top of the stack.
210170fcfcfSBram Moolenaar     idx = ectx->ec_stack.ga_len - 1;
211170fcfcfSBram Moolenaar     ectx->ec_stack.ga_len = top + 1;
212170fcfcfSBram Moolenaar     *STACK_TV_BOT(-1) = *STACK_TV(idx);
2138a7d6542SBram Moolenaar }
2148a7d6542SBram Moolenaar 
2158a7d6542SBram Moolenaar #undef STACK_TV
2168a7d6542SBram Moolenaar 
2178a7d6542SBram Moolenaar /*
2188a7d6542SBram Moolenaar  * Prepare arguments and rettv for calling a builtin or user function.
2198a7d6542SBram Moolenaar  */
2208a7d6542SBram Moolenaar     static int
2218a7d6542SBram Moolenaar call_prepare(int argcount, typval_T *argvars, ectx_T *ectx)
2228a7d6542SBram Moolenaar {
2238a7d6542SBram Moolenaar     int		idx;
2248a7d6542SBram Moolenaar     typval_T	*tv;
2258a7d6542SBram Moolenaar 
2268a7d6542SBram Moolenaar     // Move arguments from bottom of the stack to argvars[] and add terminator.
2278a7d6542SBram Moolenaar     for (idx = 0; idx < argcount; ++idx)
2288a7d6542SBram Moolenaar 	argvars[idx] = *STACK_TV_BOT(idx - argcount);
2298a7d6542SBram Moolenaar     argvars[argcount].v_type = VAR_UNKNOWN;
2308a7d6542SBram Moolenaar 
2318a7d6542SBram Moolenaar     // Result replaces the arguments on the stack.
2328a7d6542SBram Moolenaar     if (argcount > 0)
2338a7d6542SBram Moolenaar 	ectx->ec_stack.ga_len -= argcount - 1;
2348a7d6542SBram Moolenaar     else if (ga_grow(&ectx->ec_stack, 1) == FAIL)
2358a7d6542SBram Moolenaar 	return FAIL;
2368a7d6542SBram Moolenaar     else
2378a7d6542SBram Moolenaar 	++ectx->ec_stack.ga_len;
2388a7d6542SBram Moolenaar 
2398a7d6542SBram Moolenaar     // Default return value is zero.
2408a7d6542SBram Moolenaar     tv = STACK_TV_BOT(-1);
2418a7d6542SBram Moolenaar     tv->v_type = VAR_NUMBER;
2428a7d6542SBram Moolenaar     tv->vval.v_number = 0;
2438a7d6542SBram Moolenaar 
2448a7d6542SBram Moolenaar     return OK;
2458a7d6542SBram Moolenaar }
2468a7d6542SBram Moolenaar 
2478a7d6542SBram Moolenaar /*
2488a7d6542SBram Moolenaar  * Call a builtin function by index.
2498a7d6542SBram Moolenaar  */
2508a7d6542SBram Moolenaar     static int
2518a7d6542SBram Moolenaar call_bfunc(int func_idx, int argcount, ectx_T *ectx)
2528a7d6542SBram Moolenaar {
2538a7d6542SBram Moolenaar     typval_T	argvars[MAX_FUNC_ARGS];
2548a7d6542SBram Moolenaar     int		idx;
2558a7d6542SBram Moolenaar 
2568a7d6542SBram Moolenaar     if (call_prepare(argcount, argvars, ectx) == FAIL)
2578a7d6542SBram Moolenaar 	return FAIL;
2588a7d6542SBram Moolenaar 
2598a7d6542SBram Moolenaar     // Call the builtin function.
2608a7d6542SBram Moolenaar     call_internal_func_by_idx(func_idx, argvars, STACK_TV_BOT(-1));
2618a7d6542SBram Moolenaar 
2628a7d6542SBram Moolenaar     // Clear the arguments.
2638a7d6542SBram Moolenaar     for (idx = 0; idx < argcount; ++idx)
2648a7d6542SBram Moolenaar 	clear_tv(&argvars[idx]);
2658a7d6542SBram Moolenaar     return OK;
2668a7d6542SBram Moolenaar }
2678a7d6542SBram Moolenaar 
2688a7d6542SBram Moolenaar /*
2698a7d6542SBram Moolenaar  * Execute a user defined function.
2707eeefd4aSBram Moolenaar  * "iptr" can be used to replace the instruction with a more efficient one.
2718a7d6542SBram Moolenaar  */
2728a7d6542SBram Moolenaar     static int
2737eeefd4aSBram Moolenaar call_ufunc(ufunc_T *ufunc, int argcount, ectx_T *ectx, isn_T *iptr)
2748a7d6542SBram Moolenaar {
2758a7d6542SBram Moolenaar     typval_T	argvars[MAX_FUNC_ARGS];
2768a7d6542SBram Moolenaar     funcexe_T   funcexe;
2778a7d6542SBram Moolenaar     int		error;
2788a7d6542SBram Moolenaar     int		idx;
2798a7d6542SBram Moolenaar 
2808a7d6542SBram Moolenaar     if (ufunc->uf_dfunc_idx >= 0)
2817eeefd4aSBram Moolenaar     {
2827eeefd4aSBram Moolenaar 	// The function has been compiled, can call it quickly.  For a function
2837eeefd4aSBram Moolenaar 	// that was defined later: we can call it directly next time.
2847eeefd4aSBram Moolenaar 	if (iptr != NULL)
2857eeefd4aSBram Moolenaar 	{
2867eeefd4aSBram Moolenaar 	    iptr->isn_type = ISN_DCALL;
2877eeefd4aSBram Moolenaar 	    iptr->isn_arg.dfunc.cdf_idx = ufunc->uf_dfunc_idx;
2887eeefd4aSBram Moolenaar 	    iptr->isn_arg.dfunc.cdf_argcount = argcount;
2897eeefd4aSBram Moolenaar 	}
2908a7d6542SBram Moolenaar 	return call_dfunc(ufunc->uf_dfunc_idx, argcount, ectx);
2917eeefd4aSBram Moolenaar     }
2928a7d6542SBram Moolenaar 
2938a7d6542SBram Moolenaar     if (call_prepare(argcount, argvars, ectx) == FAIL)
2948a7d6542SBram Moolenaar 	return FAIL;
2958a7d6542SBram Moolenaar     vim_memset(&funcexe, 0, sizeof(funcexe));
2968a7d6542SBram Moolenaar     funcexe.evaluate = TRUE;
2978a7d6542SBram Moolenaar 
2988a7d6542SBram Moolenaar     // Call the user function.  Result goes in last position on the stack.
2998a7d6542SBram Moolenaar     // TODO: add selfdict if there is one
3008a7d6542SBram Moolenaar     error = call_user_func_check(ufunc, argcount, argvars,
3018a7d6542SBram Moolenaar 					     STACK_TV_BOT(-1), &funcexe, NULL);
3028a7d6542SBram Moolenaar 
3038a7d6542SBram Moolenaar     // Clear the arguments.
3048a7d6542SBram Moolenaar     for (idx = 0; idx < argcount; ++idx)
3058a7d6542SBram Moolenaar 	clear_tv(&argvars[idx]);
3068a7d6542SBram Moolenaar 
3078a7d6542SBram Moolenaar     if (error != FCERR_NONE)
3088a7d6542SBram Moolenaar     {
3098a7d6542SBram Moolenaar 	user_func_error(error, ufunc->uf_name);
3108a7d6542SBram Moolenaar 	return FAIL;
3118a7d6542SBram Moolenaar     }
3128a7d6542SBram Moolenaar     return OK;
3138a7d6542SBram Moolenaar }
3148a7d6542SBram Moolenaar 
3158a7d6542SBram Moolenaar /*
3168a7d6542SBram Moolenaar  * Execute a function by "name".
3178a7d6542SBram Moolenaar  * This can be a builtin function or a user function.
3187eeefd4aSBram Moolenaar  * "iptr" can be used to replace the instruction with a more efficient one.
3198a7d6542SBram Moolenaar  * Returns FAIL if not found without an error message.
3208a7d6542SBram Moolenaar  */
3218a7d6542SBram Moolenaar     static int
3227eeefd4aSBram Moolenaar call_by_name(char_u *name, int argcount, ectx_T *ectx, isn_T *iptr)
3238a7d6542SBram Moolenaar {
3248a7d6542SBram Moolenaar     ufunc_T *ufunc;
3258a7d6542SBram Moolenaar 
3268a7d6542SBram Moolenaar     if (builtin_function(name, -1))
3278a7d6542SBram Moolenaar     {
3288a7d6542SBram Moolenaar 	int func_idx = find_internal_func(name);
3298a7d6542SBram Moolenaar 
3308a7d6542SBram Moolenaar 	if (func_idx < 0)
3318a7d6542SBram Moolenaar 	    return FAIL;
3328a7d6542SBram Moolenaar 	if (check_internal_func(func_idx, argcount) == FAIL)
3338a7d6542SBram Moolenaar 	    return FAIL;
3348a7d6542SBram Moolenaar 	return call_bfunc(func_idx, argcount, ectx);
3358a7d6542SBram Moolenaar     }
3368a7d6542SBram Moolenaar 
3378a7d6542SBram Moolenaar     ufunc = find_func(name, NULL);
3388a7d6542SBram Moolenaar     if (ufunc != NULL)
3397eeefd4aSBram Moolenaar 	return call_ufunc(ufunc, argcount, ectx, iptr);
3408a7d6542SBram Moolenaar 
3418a7d6542SBram Moolenaar     return FAIL;
3428a7d6542SBram Moolenaar }
3438a7d6542SBram Moolenaar 
3448a7d6542SBram Moolenaar     static int
3458a7d6542SBram Moolenaar call_partial(typval_T *tv, int argcount, ectx_T *ectx)
3468a7d6542SBram Moolenaar {
3478a7d6542SBram Moolenaar     char_u	*name;
3488a7d6542SBram Moolenaar     int		called_emsg_before = called_emsg;
3498a7d6542SBram Moolenaar 
3508a7d6542SBram Moolenaar     if (tv->v_type == VAR_PARTIAL)
3518a7d6542SBram Moolenaar     {
3528a7d6542SBram Moolenaar 	partial_T *pt = tv->vval.v_partial;
3538a7d6542SBram Moolenaar 
3548a7d6542SBram Moolenaar 	if (pt->pt_func != NULL)
3557eeefd4aSBram Moolenaar 	    return call_ufunc(pt->pt_func, argcount, ectx, NULL);
3568a7d6542SBram Moolenaar 	name = pt->pt_name;
3578a7d6542SBram Moolenaar     }
3588a7d6542SBram Moolenaar     else
3598a7d6542SBram Moolenaar 	name = tv->vval.v_string;
3607eeefd4aSBram Moolenaar     if (call_by_name(name, argcount, ectx, NULL) == FAIL)
3618a7d6542SBram Moolenaar     {
3628a7d6542SBram Moolenaar 	if (called_emsg == called_emsg_before)
3638a7d6542SBram Moolenaar 	    semsg(_(e_unknownfunc), name);
3648a7d6542SBram Moolenaar 	return FAIL;
3658a7d6542SBram Moolenaar     }
3668a7d6542SBram Moolenaar     return OK;
3678a7d6542SBram Moolenaar }
3688a7d6542SBram Moolenaar 
3698a7d6542SBram Moolenaar /*
3700bbf722aSBram Moolenaar  * Store "tv" in variable "name".
3710bbf722aSBram Moolenaar  * This is for s: and g: variables.
3720bbf722aSBram Moolenaar  */
3730bbf722aSBram Moolenaar     static void
3740bbf722aSBram Moolenaar store_var(char_u *name, typval_T *tv)
3750bbf722aSBram Moolenaar {
3760bbf722aSBram Moolenaar     funccal_entry_T entry;
3770bbf722aSBram Moolenaar 
3780bbf722aSBram Moolenaar     save_funccal(&entry);
3790bbf722aSBram Moolenaar     set_var_const(name, NULL, tv, FALSE, 0);
3800bbf722aSBram Moolenaar     restore_funccal();
3810bbf722aSBram Moolenaar }
3820bbf722aSBram Moolenaar 
3830bbf722aSBram Moolenaar /*
3848a7d6542SBram Moolenaar  * Execute a function by "name".
3858a7d6542SBram Moolenaar  * This can be a builtin function, user function or a funcref.
3867eeefd4aSBram Moolenaar  * "iptr" can be used to replace the instruction with a more efficient one.
3878a7d6542SBram Moolenaar  */
3888a7d6542SBram Moolenaar     static int
3897eeefd4aSBram Moolenaar call_eval_func(char_u *name, int argcount, ectx_T *ectx, isn_T *iptr)
3908a7d6542SBram Moolenaar {
3918a7d6542SBram Moolenaar     int		called_emsg_before = called_emsg;
3928a7d6542SBram Moolenaar 
3937eeefd4aSBram Moolenaar     if (call_by_name(name, argcount, ectx, iptr) == FAIL
3948a7d6542SBram Moolenaar 					  && called_emsg == called_emsg_before)
3958a7d6542SBram Moolenaar     {
3968a7d6542SBram Moolenaar 	// "name" may be a variable that is a funcref or partial
3978a7d6542SBram Moolenaar 	//    if find variable
3988a7d6542SBram Moolenaar 	//      call_partial()
3998a7d6542SBram Moolenaar 	//    else
4008a7d6542SBram Moolenaar 	//      semsg(_(e_unknownfunc), name);
4018a7d6542SBram Moolenaar 	emsg("call_eval_func(partial) not implemented yet");
4028a7d6542SBram Moolenaar 	return FAIL;
4038a7d6542SBram Moolenaar     }
4048a7d6542SBram Moolenaar     return OK;
4058a7d6542SBram Moolenaar }
4068a7d6542SBram Moolenaar 
4078a7d6542SBram Moolenaar /*
4088a7d6542SBram Moolenaar  * Call a "def" function from old Vim script.
4098a7d6542SBram Moolenaar  * Return OK or FAIL.
4108a7d6542SBram Moolenaar  */
4118a7d6542SBram Moolenaar     int
4128a7d6542SBram Moolenaar call_def_function(
4138a7d6542SBram Moolenaar     ufunc_T	*ufunc,
4148a7d6542SBram Moolenaar     int		argc,		// nr of arguments
4158a7d6542SBram Moolenaar     typval_T	*argv,		// arguments
4168a7d6542SBram Moolenaar     typval_T	*rettv)		// return value
4178a7d6542SBram Moolenaar {
4188a7d6542SBram Moolenaar     ectx_T	ectx;		// execution context
4198a7d6542SBram Moolenaar     int		initial_frame_ptr;
4208a7d6542SBram Moolenaar     typval_T	*tv;
4218a7d6542SBram Moolenaar     int		idx;
4228a7d6542SBram Moolenaar     int		ret = FAIL;
4238a7d6542SBram Moolenaar     dfunc_T	*dfunc;
424170fcfcfSBram Moolenaar     int		defcount = ufunc->uf_args.ga_len - argc;
4258a7d6542SBram Moolenaar 
4268a7d6542SBram Moolenaar // Get pointer to item in the stack.
4278a7d6542SBram Moolenaar #define STACK_TV(idx) (((typval_T *)ectx.ec_stack.ga_data) + idx)
4288a7d6542SBram Moolenaar 
4298a7d6542SBram Moolenaar // Get pointer to item at the bottom of the stack, -1 is the bottom.
4308a7d6542SBram Moolenaar #undef STACK_TV_BOT
4318a7d6542SBram Moolenaar #define STACK_TV_BOT(idx) (((typval_T *)ectx.ec_stack.ga_data) + ectx.ec_stack.ga_len + idx)
4328a7d6542SBram Moolenaar 
4338a7d6542SBram Moolenaar // Get pointer to local variable on the stack.
4348a7d6542SBram Moolenaar #define STACK_TV_VAR(idx) (((typval_T *)ectx.ec_stack.ga_data) + ectx.ec_frame + STACK_FRAME_SIZE + idx)
4358a7d6542SBram Moolenaar 
4368a7d6542SBram Moolenaar     vim_memset(&ectx, 0, sizeof(ectx));
4378a7d6542SBram Moolenaar     ga_init2(&ectx.ec_stack, sizeof(typval_T), 500);
4388a7d6542SBram Moolenaar     if (ga_grow(&ectx.ec_stack, 20) == FAIL)
439*d5aec0ceSBram Moolenaar 	return FAIL;
4408a7d6542SBram Moolenaar     ectx.ec_dfunc_idx = ufunc->uf_dfunc_idx;
4418a7d6542SBram Moolenaar 
4428a7d6542SBram Moolenaar     ga_init2(&ectx.ec_trystack, sizeof(trycmd_T), 10);
4438a7d6542SBram Moolenaar 
4448a7d6542SBram Moolenaar     // Put arguments on the stack.
4458a7d6542SBram Moolenaar     for (idx = 0; idx < argc; ++idx)
4468a7d6542SBram Moolenaar     {
4478a7d6542SBram Moolenaar 	copy_tv(&argv[idx], STACK_TV_BOT(0));
4488a7d6542SBram Moolenaar 	++ectx.ec_stack.ga_len;
4498a7d6542SBram Moolenaar     }
450170fcfcfSBram Moolenaar     // Make space for omitted arguments, will store default value below.
451170fcfcfSBram Moolenaar     if (defcount > 0)
452170fcfcfSBram Moolenaar 	for (idx = 0; idx < defcount; ++idx)
453170fcfcfSBram Moolenaar 	{
454170fcfcfSBram Moolenaar 	    STACK_TV_BOT(0)->v_type = VAR_UNKNOWN;
455170fcfcfSBram Moolenaar 	    ++ectx.ec_stack.ga_len;
456170fcfcfSBram Moolenaar 	}
4578a7d6542SBram Moolenaar 
4588a7d6542SBram Moolenaar     // Frame pointer points to just after arguments.
4598a7d6542SBram Moolenaar     ectx.ec_frame = ectx.ec_stack.ga_len;
4608a7d6542SBram Moolenaar     initial_frame_ptr = ectx.ec_frame;
4618a7d6542SBram Moolenaar 
4628a7d6542SBram Moolenaar     // dummy frame entries
4638a7d6542SBram Moolenaar     for (idx = 0; idx < STACK_FRAME_SIZE; ++idx)
4648a7d6542SBram Moolenaar     {
4658a7d6542SBram Moolenaar 	STACK_TV(ectx.ec_stack.ga_len)->v_type = VAR_UNKNOWN;
4668a7d6542SBram Moolenaar 	++ectx.ec_stack.ga_len;
4678a7d6542SBram Moolenaar     }
4688a7d6542SBram Moolenaar 
4698a7d6542SBram Moolenaar     // Reserve space for local variables.
4708a7d6542SBram Moolenaar     dfunc = ((dfunc_T *)def_functions.ga_data) + ufunc->uf_dfunc_idx;
4718a7d6542SBram Moolenaar     for (idx = 0; idx < dfunc->df_varcount; ++idx)
4728a7d6542SBram Moolenaar 	STACK_TV_VAR(idx)->v_type = VAR_UNKNOWN;
4738a7d6542SBram Moolenaar     ectx.ec_stack.ga_len += dfunc->df_varcount;
4748a7d6542SBram Moolenaar 
4758a7d6542SBram Moolenaar     ectx.ec_instr = dfunc->df_instr;
476170fcfcfSBram Moolenaar 
477170fcfcfSBram Moolenaar     // Decide where to start execution, handles optional arguments.
478170fcfcfSBram Moolenaar     init_instr_idx(ufunc, argc, &ectx);
479170fcfcfSBram Moolenaar 
4808a7d6542SBram Moolenaar     for (;;)
4818a7d6542SBram Moolenaar     {
4828a7d6542SBram Moolenaar 	isn_T	    *iptr;
4838a7d6542SBram Moolenaar 	trycmd_T    *trycmd = NULL;
4848a7d6542SBram Moolenaar 
4858a7d6542SBram Moolenaar 	if (did_throw && !ectx.ec_in_catch)
4868a7d6542SBram Moolenaar 	{
4878a7d6542SBram Moolenaar 	    garray_T	*trystack = &ectx.ec_trystack;
4888a7d6542SBram Moolenaar 
4898a7d6542SBram Moolenaar 	    // An exception jumps to the first catch, finally, or returns from
4908a7d6542SBram Moolenaar 	    // the current function.
4918a7d6542SBram Moolenaar 	    if (trystack->ga_len > 0)
4928a7d6542SBram Moolenaar 		trycmd = ((trycmd_T *)trystack->ga_data) + trystack->ga_len - 1;
4938a7d6542SBram Moolenaar 	    if (trycmd != NULL && trycmd->tcd_frame == ectx.ec_frame)
4948a7d6542SBram Moolenaar 	    {
4958a7d6542SBram Moolenaar 		// jump to ":catch" or ":finally"
4968a7d6542SBram Moolenaar 		ectx.ec_in_catch = TRUE;
4978a7d6542SBram Moolenaar 		ectx.ec_iidx = trycmd->tcd_catch_idx;
4988a7d6542SBram Moolenaar 	    }
4998a7d6542SBram Moolenaar 	    else
5008a7d6542SBram Moolenaar 	    {
5018a7d6542SBram Moolenaar 		// not inside try or need to return from current functions.
5028a7d6542SBram Moolenaar 		if (ectx.ec_frame == initial_frame_ptr)
5038a7d6542SBram Moolenaar 		{
5048a7d6542SBram Moolenaar 		    // At the toplevel we are done.  Push a dummy return value.
5058a7d6542SBram Moolenaar 		    if (ga_grow(&ectx.ec_stack, 1) == FAIL)
5068a7d6542SBram Moolenaar 			goto failed;
5078a7d6542SBram Moolenaar 		    tv = STACK_TV_BOT(0);
5088a7d6542SBram Moolenaar 		    tv->v_type = VAR_NUMBER;
5098a7d6542SBram Moolenaar 		    tv->vval.v_number = 0;
5108a7d6542SBram Moolenaar 		    ++ectx.ec_stack.ga_len;
511257cc5eeSBram Moolenaar 		    need_rethrow = TRUE;
5128a7d6542SBram Moolenaar 		    goto done;
5138a7d6542SBram Moolenaar 		}
5148a7d6542SBram Moolenaar 
5158a7d6542SBram Moolenaar 		func_return(&ectx);
5168a7d6542SBram Moolenaar 	    }
5178a7d6542SBram Moolenaar 	    continue;
5188a7d6542SBram Moolenaar 	}
5198a7d6542SBram Moolenaar 
5208a7d6542SBram Moolenaar 	iptr = &ectx.ec_instr[ectx.ec_iidx++];
5218a7d6542SBram Moolenaar 	switch (iptr->isn_type)
5228a7d6542SBram Moolenaar 	{
5238a7d6542SBram Moolenaar 	    // execute Ex command line
5248a7d6542SBram Moolenaar 	    case ISN_EXEC:
5258a7d6542SBram Moolenaar 		do_cmdline_cmd(iptr->isn_arg.string);
5268a7d6542SBram Moolenaar 		break;
5278a7d6542SBram Moolenaar 
5288a7d6542SBram Moolenaar 	    // execute :echo {string} ...
5298a7d6542SBram Moolenaar 	    case ISN_ECHO:
5308a7d6542SBram Moolenaar 		{
5318a7d6542SBram Moolenaar 		    int count = iptr->isn_arg.echo.echo_count;
5328a7d6542SBram Moolenaar 		    int	atstart = TRUE;
5338a7d6542SBram Moolenaar 		    int needclr = TRUE;
5348a7d6542SBram Moolenaar 
5358a7d6542SBram Moolenaar 		    for (idx = 0; idx < count; ++idx)
5368a7d6542SBram Moolenaar 		    {
5378a7d6542SBram Moolenaar 			tv = STACK_TV_BOT(idx - count);
5388a7d6542SBram Moolenaar 			echo_one(tv, iptr->isn_arg.echo.echo_with_white,
5398a7d6542SBram Moolenaar 							   &atstart, &needclr);
5408a7d6542SBram Moolenaar 			clear_tv(tv);
5418a7d6542SBram Moolenaar 		    }
542e0807ea4SBram Moolenaar 		    if (needclr)
543e0807ea4SBram Moolenaar 			msg_clr_eos();
5448a7d6542SBram Moolenaar 		    ectx.ec_stack.ga_len -= count;
5458a7d6542SBram Moolenaar 		}
5468a7d6542SBram Moolenaar 		break;
5478a7d6542SBram Moolenaar 
548ad39c094SBram Moolenaar 	    // execute :execute {string} ...
549ad39c094SBram Moolenaar 	    case ISN_EXECUTE:
550ad39c094SBram Moolenaar 		{
551ad39c094SBram Moolenaar 		    int		count = iptr->isn_arg.number;
552ad39c094SBram Moolenaar 		    garray_T	ga;
553ad39c094SBram Moolenaar 		    char_u	buf[NUMBUFLEN];
554ad39c094SBram Moolenaar 		    char_u	*p;
555ad39c094SBram Moolenaar 		    int		len;
556ad39c094SBram Moolenaar 		    int		failed = FALSE;
557ad39c094SBram Moolenaar 
558ad39c094SBram Moolenaar 		    ga_init2(&ga, 1, 80);
559ad39c094SBram Moolenaar 		    for (idx = 0; idx < count; ++idx)
560ad39c094SBram Moolenaar 		    {
561ad39c094SBram Moolenaar 			tv = STACK_TV_BOT(idx - count);
562ad39c094SBram Moolenaar 			if (tv->v_type == VAR_CHANNEL || tv->v_type == VAR_JOB)
563ad39c094SBram Moolenaar 			{
564ad39c094SBram Moolenaar 			    emsg(_(e_inval_string));
565ad39c094SBram Moolenaar 			    break;
566ad39c094SBram Moolenaar 			}
567ad39c094SBram Moolenaar 			else
568ad39c094SBram Moolenaar 			    p = tv_get_string_buf(tv, buf);
569ad39c094SBram Moolenaar 
570ad39c094SBram Moolenaar 			len = (int)STRLEN(p);
571ad39c094SBram Moolenaar 			if (ga_grow(&ga, len + 2) == FAIL)
572ad39c094SBram Moolenaar 			    failed = TRUE;
573ad39c094SBram Moolenaar 			else
574ad39c094SBram Moolenaar 			{
575ad39c094SBram Moolenaar 			    if (ga.ga_len > 0)
576ad39c094SBram Moolenaar 				((char_u *)(ga.ga_data))[ga.ga_len++] = ' ';
577ad39c094SBram Moolenaar 			    STRCPY((char_u *)(ga.ga_data) + ga.ga_len, p);
578ad39c094SBram Moolenaar 			    ga.ga_len += len;
579ad39c094SBram Moolenaar 			}
580ad39c094SBram Moolenaar 			clear_tv(tv);
581ad39c094SBram Moolenaar 		    }
582ad39c094SBram Moolenaar 		    ectx.ec_stack.ga_len -= count;
583ad39c094SBram Moolenaar 
584ad39c094SBram Moolenaar 		    if (!failed && ga.ga_data != NULL)
585ad39c094SBram Moolenaar 			do_cmdline_cmd((char_u *)ga.ga_data);
586ad39c094SBram Moolenaar 		    ga_clear(&ga);
587ad39c094SBram Moolenaar 		}
588ad39c094SBram Moolenaar 		break;
589ad39c094SBram Moolenaar 
5908a7d6542SBram Moolenaar 	    // load local variable or argument
5918a7d6542SBram Moolenaar 	    case ISN_LOAD:
5928a7d6542SBram Moolenaar 		if (ga_grow(&ectx.ec_stack, 1) == FAIL)
5938a7d6542SBram Moolenaar 		    goto failed;
5948a7d6542SBram Moolenaar 		copy_tv(STACK_TV_VAR(iptr->isn_arg.number), STACK_TV_BOT(0));
5958a7d6542SBram Moolenaar 		++ectx.ec_stack.ga_len;
5968a7d6542SBram Moolenaar 		break;
5978a7d6542SBram Moolenaar 
5988a7d6542SBram Moolenaar 	    // load v: variable
5998a7d6542SBram Moolenaar 	    case ISN_LOADV:
6008a7d6542SBram Moolenaar 		if (ga_grow(&ectx.ec_stack, 1) == FAIL)
6018a7d6542SBram Moolenaar 		    goto failed;
6028a7d6542SBram Moolenaar 		copy_tv(get_vim_var_tv(iptr->isn_arg.number), STACK_TV_BOT(0));
6038a7d6542SBram Moolenaar 		++ectx.ec_stack.ga_len;
6048a7d6542SBram Moolenaar 		break;
6058a7d6542SBram Moolenaar 
606b283a8a6SBram Moolenaar 	    // load s: variable in Vim9 script
6078a7d6542SBram Moolenaar 	    case ISN_LOADSCRIPT:
6088a7d6542SBram Moolenaar 		{
6098a7d6542SBram Moolenaar 		    scriptitem_T *si =
61021b9e977SBram Moolenaar 				  SCRIPT_ITEM(iptr->isn_arg.script.script_sid);
6118a7d6542SBram Moolenaar 		    svar_T	 *sv;
6128a7d6542SBram Moolenaar 
6138a7d6542SBram Moolenaar 		    sv = ((svar_T *)si->sn_var_vals.ga_data)
6148a7d6542SBram Moolenaar 					     + iptr->isn_arg.script.script_idx;
6158a7d6542SBram Moolenaar 		    if (ga_grow(&ectx.ec_stack, 1) == FAIL)
6168a7d6542SBram Moolenaar 			goto failed;
6178a7d6542SBram Moolenaar 		    copy_tv(sv->sv_tv, STACK_TV_BOT(0));
6188a7d6542SBram Moolenaar 		    ++ectx.ec_stack.ga_len;
6198a7d6542SBram Moolenaar 		}
6208a7d6542SBram Moolenaar 		break;
6218a7d6542SBram Moolenaar 
6228a7d6542SBram Moolenaar 	    // load s: variable in old script
6238a7d6542SBram Moolenaar 	    case ISN_LOADS:
6248a7d6542SBram Moolenaar 		{
625b283a8a6SBram Moolenaar 		    hashtab_T	*ht = &SCRIPT_VARS(
626b283a8a6SBram Moolenaar 					       iptr->isn_arg.loadstore.ls_sid);
627b283a8a6SBram Moolenaar 		    char_u	*name = iptr->isn_arg.loadstore.ls_name;
6288a7d6542SBram Moolenaar 		    dictitem_T	*di = find_var_in_ht(ht, 0, name, TRUE);
6290bbf722aSBram Moolenaar 
6308a7d6542SBram Moolenaar 		    if (di == NULL)
6318a7d6542SBram Moolenaar 		    {
632b283a8a6SBram Moolenaar 			semsg(_(e_undefvar), name);
6338a7d6542SBram Moolenaar 			goto failed;
6348a7d6542SBram Moolenaar 		    }
6358a7d6542SBram Moolenaar 		    else
6368a7d6542SBram Moolenaar 		    {
6378a7d6542SBram Moolenaar 			if (ga_grow(&ectx.ec_stack, 1) == FAIL)
6388a7d6542SBram Moolenaar 			    goto failed;
6398a7d6542SBram Moolenaar 			copy_tv(&di->di_tv, STACK_TV_BOT(0));
6408a7d6542SBram Moolenaar 			++ectx.ec_stack.ga_len;
6418a7d6542SBram Moolenaar 		    }
6428a7d6542SBram Moolenaar 		}
6438a7d6542SBram Moolenaar 		break;
6448a7d6542SBram Moolenaar 
6458a7d6542SBram Moolenaar 	    // load g: variable
6468a7d6542SBram Moolenaar 	    case ISN_LOADG:
6478a7d6542SBram Moolenaar 		{
6480bbf722aSBram Moolenaar 		    dictitem_T *di = find_var_in_ht(get_globvar_ht(), 0,
6498a7d6542SBram Moolenaar 						   iptr->isn_arg.string, TRUE);
6500bbf722aSBram Moolenaar 
6518a7d6542SBram Moolenaar 		    if (di == NULL)
6528a7d6542SBram Moolenaar 		    {
6538a7d6542SBram Moolenaar 			semsg(_("E121: Undefined variable: g:%s"),
6548a7d6542SBram Moolenaar 							 iptr->isn_arg.string);
6558a7d6542SBram Moolenaar 			goto failed;
6568a7d6542SBram Moolenaar 		    }
6578a7d6542SBram Moolenaar 		    else
6588a7d6542SBram Moolenaar 		    {
6598a7d6542SBram Moolenaar 			if (ga_grow(&ectx.ec_stack, 1) == FAIL)
6608a7d6542SBram Moolenaar 			    goto failed;
6618a7d6542SBram Moolenaar 			copy_tv(&di->di_tv, STACK_TV_BOT(0));
6628a7d6542SBram Moolenaar 			++ectx.ec_stack.ga_len;
6638a7d6542SBram Moolenaar 		    }
6648a7d6542SBram Moolenaar 		}
6658a7d6542SBram Moolenaar 		break;
6668a7d6542SBram Moolenaar 
6678a7d6542SBram Moolenaar 	    // load &option
6688a7d6542SBram Moolenaar 	    case ISN_LOADOPT:
6698a7d6542SBram Moolenaar 		{
6708a7d6542SBram Moolenaar 		    typval_T	optval;
6718a7d6542SBram Moolenaar 		    char_u	*name = iptr->isn_arg.string;
6728a7d6542SBram Moolenaar 
6738a7d6542SBram Moolenaar 		    if (ga_grow(&ectx.ec_stack, 1) == FAIL)
6748a7d6542SBram Moolenaar 			goto failed;
67558ceca5cSBram Moolenaar 		    if (get_option_tv(&name, &optval, TRUE) == FAIL)
67658ceca5cSBram Moolenaar 			goto failed;
6778a7d6542SBram Moolenaar 		    *STACK_TV_BOT(0) = optval;
6788a7d6542SBram Moolenaar 		    ++ectx.ec_stack.ga_len;
6798a7d6542SBram Moolenaar 		}
6808a7d6542SBram Moolenaar 		break;
6818a7d6542SBram Moolenaar 
6828a7d6542SBram Moolenaar 	    // load $ENV
6838a7d6542SBram Moolenaar 	    case ISN_LOADENV:
6848a7d6542SBram Moolenaar 		{
6858a7d6542SBram Moolenaar 		    typval_T	optval;
6868a7d6542SBram Moolenaar 		    char_u	*name = iptr->isn_arg.string;
6878a7d6542SBram Moolenaar 
6888a7d6542SBram Moolenaar 		    if (ga_grow(&ectx.ec_stack, 1) == FAIL)
6898a7d6542SBram Moolenaar 			goto failed;
6900bbf722aSBram Moolenaar 		    // name is always valid, checked when compiling
6910bbf722aSBram Moolenaar 		    (void)get_env_tv(&name, &optval, TRUE);
6928a7d6542SBram Moolenaar 		    *STACK_TV_BOT(0) = optval;
6938a7d6542SBram Moolenaar 		    ++ectx.ec_stack.ga_len;
6948a7d6542SBram Moolenaar 		}
6958a7d6542SBram Moolenaar 		break;
6968a7d6542SBram Moolenaar 
6978a7d6542SBram Moolenaar 	    // load @register
6988a7d6542SBram Moolenaar 	    case ISN_LOADREG:
6998a7d6542SBram Moolenaar 		if (ga_grow(&ectx.ec_stack, 1) == FAIL)
7008a7d6542SBram Moolenaar 		    goto failed;
7018a7d6542SBram Moolenaar 		tv = STACK_TV_BOT(0);
7028a7d6542SBram Moolenaar 		tv->v_type = VAR_STRING;
7038a7d6542SBram Moolenaar 		tv->vval.v_string = get_reg_contents(
7048a7d6542SBram Moolenaar 					  iptr->isn_arg.number, GREG_EXPR_SRC);
7058a7d6542SBram Moolenaar 		++ectx.ec_stack.ga_len;
7068a7d6542SBram Moolenaar 		break;
7078a7d6542SBram Moolenaar 
7088a7d6542SBram Moolenaar 	    // store local variable
7098a7d6542SBram Moolenaar 	    case ISN_STORE:
7108a7d6542SBram Moolenaar 		--ectx.ec_stack.ga_len;
7118a7d6542SBram Moolenaar 		tv = STACK_TV_VAR(iptr->isn_arg.number);
7128a7d6542SBram Moolenaar 		clear_tv(tv);
7138a7d6542SBram Moolenaar 		*tv = *STACK_TV_BOT(0);
7148a7d6542SBram Moolenaar 		break;
7158a7d6542SBram Moolenaar 
716b283a8a6SBram Moolenaar 	    // store s: variable in old script
717b283a8a6SBram Moolenaar 	    case ISN_STORES:
718b283a8a6SBram Moolenaar 		{
719b283a8a6SBram Moolenaar 		    hashtab_T	*ht = &SCRIPT_VARS(
720b283a8a6SBram Moolenaar 					       iptr->isn_arg.loadstore.ls_sid);
721b283a8a6SBram Moolenaar 		    char_u	*name = iptr->isn_arg.loadstore.ls_name;
7220bbf722aSBram Moolenaar 		    dictitem_T	*di = find_var_in_ht(ht, 0, name + 2, TRUE);
723b283a8a6SBram Moolenaar 
724b283a8a6SBram Moolenaar 		    --ectx.ec_stack.ga_len;
7250bbf722aSBram Moolenaar 		    if (di == NULL)
7260bbf722aSBram Moolenaar 			store_var(iptr->isn_arg.string, STACK_TV_BOT(0));
7270bbf722aSBram Moolenaar 		    else
7280bbf722aSBram Moolenaar 		    {
729b283a8a6SBram Moolenaar 			clear_tv(&di->di_tv);
730b283a8a6SBram Moolenaar 			di->di_tv = *STACK_TV_BOT(0);
731b283a8a6SBram Moolenaar 		    }
7320bbf722aSBram Moolenaar 		}
733b283a8a6SBram Moolenaar 		break;
734b283a8a6SBram Moolenaar 
735b283a8a6SBram Moolenaar 	    // store script-local variable in Vim9 script
7368a7d6542SBram Moolenaar 	    case ISN_STORESCRIPT:
7378a7d6542SBram Moolenaar 		{
73821b9e977SBram Moolenaar 		    scriptitem_T *si = SCRIPT_ITEM(
7398a7d6542SBram Moolenaar 					      iptr->isn_arg.script.script_sid);
7408a7d6542SBram Moolenaar 		    svar_T	 *sv = ((svar_T *)si->sn_var_vals.ga_data)
7418a7d6542SBram Moolenaar 					     + iptr->isn_arg.script.script_idx;
7428a7d6542SBram Moolenaar 
7438a7d6542SBram Moolenaar 		    --ectx.ec_stack.ga_len;
7448a7d6542SBram Moolenaar 		    clear_tv(sv->sv_tv);
7458a7d6542SBram Moolenaar 		    *sv->sv_tv = *STACK_TV_BOT(0);
7468a7d6542SBram Moolenaar 		}
7478a7d6542SBram Moolenaar 		break;
7488a7d6542SBram Moolenaar 
7498a7d6542SBram Moolenaar 	    // store option
7508a7d6542SBram Moolenaar 	    case ISN_STOREOPT:
7518a7d6542SBram Moolenaar 		{
7528a7d6542SBram Moolenaar 		    long	n = 0;
7538a7d6542SBram Moolenaar 		    char_u	*s = NULL;
7548a7d6542SBram Moolenaar 		    char	*msg;
7558a7d6542SBram Moolenaar 
7568a7d6542SBram Moolenaar 		    --ectx.ec_stack.ga_len;
7578a7d6542SBram Moolenaar 		    tv = STACK_TV_BOT(0);
7588a7d6542SBram Moolenaar 		    if (tv->v_type == VAR_STRING)
75997a2af39SBram Moolenaar 		    {
7608a7d6542SBram Moolenaar 			s = tv->vval.v_string;
76197a2af39SBram Moolenaar 			if (s == NULL)
76297a2af39SBram Moolenaar 			    s = (char_u *)"";
76397a2af39SBram Moolenaar 		    }
7648a7d6542SBram Moolenaar 		    else if (tv->v_type == VAR_NUMBER)
7658a7d6542SBram Moolenaar 			n = tv->vval.v_number;
7668a7d6542SBram Moolenaar 		    else
7678a7d6542SBram Moolenaar 		    {
7688a7d6542SBram Moolenaar 			emsg(_("E1051: Expected string or number"));
7698a7d6542SBram Moolenaar 			goto failed;
7708a7d6542SBram Moolenaar 		    }
7718a7d6542SBram Moolenaar 		    msg = set_option_value(iptr->isn_arg.storeopt.so_name,
7728a7d6542SBram Moolenaar 					n, s, iptr->isn_arg.storeopt.so_flags);
7738a7d6542SBram Moolenaar 		    if (msg != NULL)
7748a7d6542SBram Moolenaar 		    {
7758a7d6542SBram Moolenaar 			emsg(_(msg));
7768a7d6542SBram Moolenaar 			goto failed;
7778a7d6542SBram Moolenaar 		    }
7788a7d6542SBram Moolenaar 		    clear_tv(tv);
7798a7d6542SBram Moolenaar 		}
7808a7d6542SBram Moolenaar 		break;
7818a7d6542SBram Moolenaar 
782b283a8a6SBram Moolenaar 	    // store $ENV
783b283a8a6SBram Moolenaar 	    case ISN_STOREENV:
784b283a8a6SBram Moolenaar 		--ectx.ec_stack.ga_len;
785b283a8a6SBram Moolenaar 		vim_setenv_ext(iptr->isn_arg.string,
786b283a8a6SBram Moolenaar 					       tv_get_string(STACK_TV_BOT(0)));
787b283a8a6SBram Moolenaar 		break;
788b283a8a6SBram Moolenaar 
789b283a8a6SBram Moolenaar 	    // store @r
790b283a8a6SBram Moolenaar 	    case ISN_STOREREG:
791b283a8a6SBram Moolenaar 		{
792b283a8a6SBram Moolenaar 		    int	reg = iptr->isn_arg.number;
793b283a8a6SBram Moolenaar 
794b283a8a6SBram Moolenaar 		    --ectx.ec_stack.ga_len;
795401d9ffbSBram Moolenaar 		    tv = STACK_TV_BOT(0);
796b283a8a6SBram Moolenaar 		    write_reg_contents(reg == '@' ? '"' : reg,
797401d9ffbSBram Moolenaar 						 tv_get_string(tv), -1, FALSE);
798401d9ffbSBram Moolenaar 		    clear_tv(tv);
799b283a8a6SBram Moolenaar 		}
800b283a8a6SBram Moolenaar 		break;
801b283a8a6SBram Moolenaar 
802b283a8a6SBram Moolenaar 	    // store v: variable
803b283a8a6SBram Moolenaar 	    case ISN_STOREV:
804b283a8a6SBram Moolenaar 		--ectx.ec_stack.ga_len;
805b283a8a6SBram Moolenaar 		if (set_vim_var_tv(iptr->isn_arg.number, STACK_TV_BOT(0))
806b283a8a6SBram Moolenaar 								       == FAIL)
807b283a8a6SBram Moolenaar 		    goto failed;
808b283a8a6SBram Moolenaar 		break;
809b283a8a6SBram Moolenaar 
8108a7d6542SBram Moolenaar 	    // store g: variable
8118a7d6542SBram Moolenaar 	    case ISN_STOREG:
8128a7d6542SBram Moolenaar 		{
8138a7d6542SBram Moolenaar 		    dictitem_T *di;
8148a7d6542SBram Moolenaar 
8158a7d6542SBram Moolenaar 		    --ectx.ec_stack.ga_len;
8168a7d6542SBram Moolenaar 		    di = find_var_in_ht(get_globvar_ht(), 0,
817401d9ffbSBram Moolenaar 					       iptr->isn_arg.string + 2, TRUE);
8188a7d6542SBram Moolenaar 		    if (di == NULL)
8190bbf722aSBram Moolenaar 			store_var(iptr->isn_arg.string, STACK_TV_BOT(0));
8208a7d6542SBram Moolenaar 		    else
8218a7d6542SBram Moolenaar 		    {
8228a7d6542SBram Moolenaar 			clear_tv(&di->di_tv);
8238a7d6542SBram Moolenaar 			di->di_tv = *STACK_TV_BOT(0);
8248a7d6542SBram Moolenaar 		    }
8258a7d6542SBram Moolenaar 		}
8268a7d6542SBram Moolenaar 		break;
8278a7d6542SBram Moolenaar 
8288a7d6542SBram Moolenaar 	    // store number in local variable
8298a7d6542SBram Moolenaar 	    case ISN_STORENR:
8308a7d6542SBram Moolenaar 		tv = STACK_TV_VAR(iptr->isn_arg.storenr.str_idx);
8318a7d6542SBram Moolenaar 		clear_tv(tv);
8328a7d6542SBram Moolenaar 		tv->v_type = VAR_NUMBER;
8338a7d6542SBram Moolenaar 		tv->vval.v_number = iptr->isn_arg.storenr.str_val;
8348a7d6542SBram Moolenaar 		break;
8358a7d6542SBram Moolenaar 
8368a7d6542SBram Moolenaar 	    // push constant
8378a7d6542SBram Moolenaar 	    case ISN_PUSHNR:
8388a7d6542SBram Moolenaar 	    case ISN_PUSHBOOL:
8398a7d6542SBram Moolenaar 	    case ISN_PUSHSPEC:
8408a7d6542SBram Moolenaar 	    case ISN_PUSHF:
8418a7d6542SBram Moolenaar 	    case ISN_PUSHS:
8428a7d6542SBram Moolenaar 	    case ISN_PUSHBLOB:
8438a7d6542SBram Moolenaar 		if (ga_grow(&ectx.ec_stack, 1) == FAIL)
8448a7d6542SBram Moolenaar 		    goto failed;
8458a7d6542SBram Moolenaar 		tv = STACK_TV_BOT(0);
8468a7d6542SBram Moolenaar 		++ectx.ec_stack.ga_len;
8478a7d6542SBram Moolenaar 		switch (iptr->isn_type)
8488a7d6542SBram Moolenaar 		{
8498a7d6542SBram Moolenaar 		    case ISN_PUSHNR:
8508a7d6542SBram Moolenaar 			tv->v_type = VAR_NUMBER;
8518a7d6542SBram Moolenaar 			tv->vval.v_number = iptr->isn_arg.number;
8528a7d6542SBram Moolenaar 			break;
8538a7d6542SBram Moolenaar 		    case ISN_PUSHBOOL:
8548a7d6542SBram Moolenaar 			tv->v_type = VAR_BOOL;
8558a7d6542SBram Moolenaar 			tv->vval.v_number = iptr->isn_arg.number;
8568a7d6542SBram Moolenaar 			break;
8578a7d6542SBram Moolenaar 		    case ISN_PUSHSPEC:
8588a7d6542SBram Moolenaar 			tv->v_type = VAR_SPECIAL;
8598a7d6542SBram Moolenaar 			tv->vval.v_number = iptr->isn_arg.number;
8608a7d6542SBram Moolenaar 			break;
8618a7d6542SBram Moolenaar #ifdef FEAT_FLOAT
8628a7d6542SBram Moolenaar 		    case ISN_PUSHF:
8638a7d6542SBram Moolenaar 			tv->v_type = VAR_FLOAT;
8648a7d6542SBram Moolenaar 			tv->vval.v_float = iptr->isn_arg.fnumber;
8658a7d6542SBram Moolenaar 			break;
8668a7d6542SBram Moolenaar #endif
8678a7d6542SBram Moolenaar 		    case ISN_PUSHBLOB:
8688a7d6542SBram Moolenaar 			blob_copy(iptr->isn_arg.blob, tv);
8698a7d6542SBram Moolenaar 			break;
8708a7d6542SBram Moolenaar 		    default:
8718a7d6542SBram Moolenaar 			tv->v_type = VAR_STRING;
8728a7d6542SBram Moolenaar 			tv->vval.v_string = vim_strsave(iptr->isn_arg.string);
8738a7d6542SBram Moolenaar 		}
8748a7d6542SBram Moolenaar 		break;
8758a7d6542SBram Moolenaar 
8768a7d6542SBram Moolenaar 	    // create a list from items on the stack; uses a single allocation
8778a7d6542SBram Moolenaar 	    // for the list header and the items
8788a7d6542SBram Moolenaar 	    case ISN_NEWLIST:
8798a7d6542SBram Moolenaar 		{
8808a7d6542SBram Moolenaar 		    int	    count = iptr->isn_arg.number;
8818a7d6542SBram Moolenaar 		    list_T  *list = list_alloc_with_items(count);
8828a7d6542SBram Moolenaar 
8838a7d6542SBram Moolenaar 		    if (list == NULL)
8848a7d6542SBram Moolenaar 			goto failed;
8858a7d6542SBram Moolenaar 		    for (idx = 0; idx < count; ++idx)
8868a7d6542SBram Moolenaar 			list_set_item(list, idx, STACK_TV_BOT(idx - count));
8878a7d6542SBram Moolenaar 
8888a7d6542SBram Moolenaar 		    if (count > 0)
8898a7d6542SBram Moolenaar 			ectx.ec_stack.ga_len -= count - 1;
8908a7d6542SBram Moolenaar 		    else if (ga_grow(&ectx.ec_stack, 1) == FAIL)
8918a7d6542SBram Moolenaar 			goto failed;
8928a7d6542SBram Moolenaar 		    else
8938a7d6542SBram Moolenaar 			++ectx.ec_stack.ga_len;
8948a7d6542SBram Moolenaar 		    tv = STACK_TV_BOT(-1);
8958a7d6542SBram Moolenaar 		    tv->v_type = VAR_LIST;
8968a7d6542SBram Moolenaar 		    tv->vval.v_list = list;
8978a7d6542SBram Moolenaar 		    ++list->lv_refcount;
8988a7d6542SBram Moolenaar 		}
8998a7d6542SBram Moolenaar 		break;
9008a7d6542SBram Moolenaar 
9018a7d6542SBram Moolenaar 	    // create a dict from items on the stack
9028a7d6542SBram Moolenaar 	    case ISN_NEWDICT:
9038a7d6542SBram Moolenaar 		{
9048a7d6542SBram Moolenaar 		    int	    count = iptr->isn_arg.number;
9058a7d6542SBram Moolenaar 		    dict_T  *dict = dict_alloc();
9068a7d6542SBram Moolenaar 		    dictitem_T *item;
9078a7d6542SBram Moolenaar 
9088a7d6542SBram Moolenaar 		    if (dict == NULL)
9098a7d6542SBram Moolenaar 			goto failed;
9108a7d6542SBram Moolenaar 		    for (idx = 0; idx < count; ++idx)
9118a7d6542SBram Moolenaar 		    {
9128a7d6542SBram Moolenaar 			// check key type is VAR_STRING
9138a7d6542SBram Moolenaar 			tv = STACK_TV_BOT(2 * (idx - count));
9148a7d6542SBram Moolenaar 			item = dictitem_alloc(tv->vval.v_string);
9158a7d6542SBram Moolenaar 			clear_tv(tv);
9168a7d6542SBram Moolenaar 			if (item == NULL)
9178a7d6542SBram Moolenaar 			    goto failed;
9188a7d6542SBram Moolenaar 			item->di_tv = *STACK_TV_BOT(2 * (idx - count) + 1);
9198a7d6542SBram Moolenaar 			item->di_tv.v_lock = 0;
9208a7d6542SBram Moolenaar 			if (dict_add(dict, item) == FAIL)
9218a7d6542SBram Moolenaar 			    goto failed;
9228a7d6542SBram Moolenaar 		    }
9238a7d6542SBram Moolenaar 
9248a7d6542SBram Moolenaar 		    if (count > 0)
9258a7d6542SBram Moolenaar 			ectx.ec_stack.ga_len -= 2 * count - 1;
9268a7d6542SBram Moolenaar 		    else if (ga_grow(&ectx.ec_stack, 1) == FAIL)
9278a7d6542SBram Moolenaar 			goto failed;
9288a7d6542SBram Moolenaar 		    else
9298a7d6542SBram Moolenaar 			++ectx.ec_stack.ga_len;
9308a7d6542SBram Moolenaar 		    tv = STACK_TV_BOT(-1);
9318a7d6542SBram Moolenaar 		    tv->v_type = VAR_DICT;
9328a7d6542SBram Moolenaar 		    tv->vval.v_dict = dict;
9338a7d6542SBram Moolenaar 		    ++dict->dv_refcount;
9348a7d6542SBram Moolenaar 		}
9358a7d6542SBram Moolenaar 		break;
9368a7d6542SBram Moolenaar 
9378a7d6542SBram Moolenaar 	    // call a :def function
9388a7d6542SBram Moolenaar 	    case ISN_DCALL:
9398a7d6542SBram Moolenaar 		if (call_dfunc(iptr->isn_arg.dfunc.cdf_idx,
9408a7d6542SBram Moolenaar 			      iptr->isn_arg.dfunc.cdf_argcount,
9418a7d6542SBram Moolenaar 			      &ectx) == FAIL)
9428a7d6542SBram Moolenaar 		    goto failed;
9438a7d6542SBram Moolenaar 		break;
9448a7d6542SBram Moolenaar 
9458a7d6542SBram Moolenaar 	    // call a builtin function
9468a7d6542SBram Moolenaar 	    case ISN_BCALL:
9478a7d6542SBram Moolenaar 		SOURCING_LNUM = iptr->isn_lnum;
9488a7d6542SBram Moolenaar 		if (call_bfunc(iptr->isn_arg.bfunc.cbf_idx,
9498a7d6542SBram Moolenaar 			      iptr->isn_arg.bfunc.cbf_argcount,
9508a7d6542SBram Moolenaar 			      &ectx) == FAIL)
9518a7d6542SBram Moolenaar 		    goto failed;
9528a7d6542SBram Moolenaar 		break;
9538a7d6542SBram Moolenaar 
9548a7d6542SBram Moolenaar 	    // call a funcref or partial
9558a7d6542SBram Moolenaar 	    case ISN_PCALL:
9568a7d6542SBram Moolenaar 		{
9578a7d6542SBram Moolenaar 		    cpfunc_T	*pfunc = &iptr->isn_arg.pfunc;
9588a7d6542SBram Moolenaar 		    int		r;
9598a7d6542SBram Moolenaar 		    typval_T	partial;
9608a7d6542SBram Moolenaar 
9618a7d6542SBram Moolenaar 		    SOURCING_LNUM = iptr->isn_lnum;
9628a7d6542SBram Moolenaar 		    if (pfunc->cpf_top)
9638a7d6542SBram Moolenaar 		    {
9648a7d6542SBram Moolenaar 			// funcref is above the arguments
9658a7d6542SBram Moolenaar 			tv = STACK_TV_BOT(-pfunc->cpf_argcount - 1);
9668a7d6542SBram Moolenaar 		    }
9678a7d6542SBram Moolenaar 		    else
9688a7d6542SBram Moolenaar 		    {
9698a7d6542SBram Moolenaar 			// Get the funcref from the stack.
9708a7d6542SBram Moolenaar 			--ectx.ec_stack.ga_len;
9718a7d6542SBram Moolenaar 			partial = *STACK_TV_BOT(0);
9728a7d6542SBram Moolenaar 			tv = &partial;
9738a7d6542SBram Moolenaar 		    }
9748a7d6542SBram Moolenaar 		    r = call_partial(tv, pfunc->cpf_argcount, &ectx);
9758a7d6542SBram Moolenaar 		    if (tv == &partial)
9768a7d6542SBram Moolenaar 			clear_tv(&partial);
9778a7d6542SBram Moolenaar 		    if (r == FAIL)
9788a7d6542SBram Moolenaar 			goto failed;
9798a7d6542SBram Moolenaar 
9808a7d6542SBram Moolenaar 		    if (pfunc->cpf_top)
9818a7d6542SBram Moolenaar 		    {
9828a7d6542SBram Moolenaar 			// Get the funcref from the stack, overwrite with the
9838a7d6542SBram Moolenaar 			// return value.
9848a7d6542SBram Moolenaar 			clear_tv(tv);
9858a7d6542SBram Moolenaar 			--ectx.ec_stack.ga_len;
9868a7d6542SBram Moolenaar 			*STACK_TV_BOT(-1) = *STACK_TV_BOT(0);
9878a7d6542SBram Moolenaar 		    }
9888a7d6542SBram Moolenaar 		}
9898a7d6542SBram Moolenaar 		break;
9908a7d6542SBram Moolenaar 
9918a7d6542SBram Moolenaar 	    // call a user defined function or funcref/partial
9928a7d6542SBram Moolenaar 	    case ISN_UCALL:
9938a7d6542SBram Moolenaar 		{
9948a7d6542SBram Moolenaar 		    cufunc_T	*cufunc = &iptr->isn_arg.ufunc;
9958a7d6542SBram Moolenaar 
9968a7d6542SBram Moolenaar 		    SOURCING_LNUM = iptr->isn_lnum;
9978a7d6542SBram Moolenaar 		    if (call_eval_func(cufunc->cuf_name,
9987eeefd4aSBram Moolenaar 				    cufunc->cuf_argcount, &ectx, iptr) == FAIL)
9998a7d6542SBram Moolenaar 			goto failed;
10008a7d6542SBram Moolenaar 		}
10018a7d6542SBram Moolenaar 		break;
10028a7d6542SBram Moolenaar 
10038a7d6542SBram Moolenaar 	    // return from a :def function call
10048a7d6542SBram Moolenaar 	    case ISN_RETURN:
10058a7d6542SBram Moolenaar 		{
10068cbd6dfcSBram Moolenaar 		    garray_T	*trystack = &ectx.ec_trystack;
10078cbd6dfcSBram Moolenaar 
10088cbd6dfcSBram Moolenaar 		    if (trystack->ga_len > 0)
10098cbd6dfcSBram Moolenaar 			trycmd = ((trycmd_T *)trystack->ga_data)
10108cbd6dfcSBram Moolenaar 							+ trystack->ga_len - 1;
10118a7d6542SBram Moolenaar 		    if (trycmd != NULL && trycmd->tcd_frame == ectx.ec_frame
10128a7d6542SBram Moolenaar 			    && trycmd->tcd_finally_idx != 0)
10138a7d6542SBram Moolenaar 		    {
10148a7d6542SBram Moolenaar 			// jump to ":finally"
10158a7d6542SBram Moolenaar 			ectx.ec_iidx = trycmd->tcd_finally_idx;
10168a7d6542SBram Moolenaar 			trycmd->tcd_return = TRUE;
10178a7d6542SBram Moolenaar 		    }
10188a7d6542SBram Moolenaar 		    else
10198a7d6542SBram Moolenaar 		    {
10208a7d6542SBram Moolenaar 			// Restore previous function. If the frame pointer
10218a7d6542SBram Moolenaar 			// is zero then there is none and we are done.
10228a7d6542SBram Moolenaar 			if (ectx.ec_frame == initial_frame_ptr)
10238a7d6542SBram Moolenaar 			    goto done;
10248a7d6542SBram Moolenaar 
10258a7d6542SBram Moolenaar 			func_return(&ectx);
10268a7d6542SBram Moolenaar 		    }
10278a7d6542SBram Moolenaar 		}
10288a7d6542SBram Moolenaar 		break;
10298a7d6542SBram Moolenaar 
10308a7d6542SBram Moolenaar 	    // push a function reference to a compiled function
10318a7d6542SBram Moolenaar 	    case ISN_FUNCREF:
10328a7d6542SBram Moolenaar 		{
10338a7d6542SBram Moolenaar 		    partial_T   *pt = NULL;
10348a7d6542SBram Moolenaar 
10358a7d6542SBram Moolenaar 		    pt = ALLOC_CLEAR_ONE(partial_T);
10368a7d6542SBram Moolenaar 		    if (pt == NULL)
10378a7d6542SBram Moolenaar 			goto failed;
10388a7d6542SBram Moolenaar 		    dfunc = ((dfunc_T *)def_functions.ga_data)
10398a7d6542SBram Moolenaar 							+ iptr->isn_arg.number;
10408a7d6542SBram Moolenaar 		    pt->pt_func = dfunc->df_ufunc;
10418a7d6542SBram Moolenaar 		    pt->pt_refcount = 1;
10428a7d6542SBram Moolenaar 		    ++dfunc->df_ufunc->uf_refcount;
10438a7d6542SBram Moolenaar 
10448a7d6542SBram Moolenaar 		    if (ga_grow(&ectx.ec_stack, 1) == FAIL)
10458a7d6542SBram Moolenaar 			goto failed;
10468a7d6542SBram Moolenaar 		    tv = STACK_TV_BOT(0);
10478a7d6542SBram Moolenaar 		    ++ectx.ec_stack.ga_len;
10488a7d6542SBram Moolenaar 		    tv->vval.v_partial = pt;
10498a7d6542SBram Moolenaar 		    tv->v_type = VAR_PARTIAL;
10508a7d6542SBram Moolenaar 		}
10518a7d6542SBram Moolenaar 		break;
10528a7d6542SBram Moolenaar 
10538a7d6542SBram Moolenaar 	    // jump if a condition is met
10548a7d6542SBram Moolenaar 	    case ISN_JUMP:
10558a7d6542SBram Moolenaar 		{
10568a7d6542SBram Moolenaar 		    jumpwhen_T	when = iptr->isn_arg.jump.jump_when;
10578a7d6542SBram Moolenaar 		    int		jump = TRUE;
10588a7d6542SBram Moolenaar 
10598a7d6542SBram Moolenaar 		    if (when != JUMP_ALWAYS)
10608a7d6542SBram Moolenaar 		    {
10618a7d6542SBram Moolenaar 			tv = STACK_TV_BOT(-1);
10628a7d6542SBram Moolenaar 			jump = tv2bool(tv);
10638a7d6542SBram Moolenaar 			if (when == JUMP_IF_FALSE
10648a7d6542SBram Moolenaar 					     || when == JUMP_AND_KEEP_IF_FALSE)
10658a7d6542SBram Moolenaar 			    jump = !jump;
1066777770fbSBram Moolenaar 			if (when == JUMP_IF_FALSE || !jump)
10678a7d6542SBram Moolenaar 			{
10688a7d6542SBram Moolenaar 			    // drop the value from the stack
10698a7d6542SBram Moolenaar 			    clear_tv(tv);
10708a7d6542SBram Moolenaar 			    --ectx.ec_stack.ga_len;
10718a7d6542SBram Moolenaar 			}
10728a7d6542SBram Moolenaar 		    }
10738a7d6542SBram Moolenaar 		    if (jump)
10748a7d6542SBram Moolenaar 			ectx.ec_iidx = iptr->isn_arg.jump.jump_where;
10758a7d6542SBram Moolenaar 		}
10768a7d6542SBram Moolenaar 		break;
10778a7d6542SBram Moolenaar 
10788a7d6542SBram Moolenaar 	    // top of a for loop
10798a7d6542SBram Moolenaar 	    case ISN_FOR:
10808a7d6542SBram Moolenaar 		{
10818a7d6542SBram Moolenaar 		    list_T	*list = STACK_TV_BOT(-1)->vval.v_list;
10828a7d6542SBram Moolenaar 		    typval_T	*idxtv =
10838a7d6542SBram Moolenaar 				   STACK_TV_VAR(iptr->isn_arg.forloop.for_idx);
10848a7d6542SBram Moolenaar 
10858a7d6542SBram Moolenaar 		    // push the next item from the list
10868a7d6542SBram Moolenaar 		    if (ga_grow(&ectx.ec_stack, 1) == FAIL)
10878a7d6542SBram Moolenaar 			goto failed;
10888a7d6542SBram Moolenaar 		    if (++idxtv->vval.v_number >= list->lv_len)
10898a7d6542SBram Moolenaar 			// past the end of the list, jump to "endfor"
10908a7d6542SBram Moolenaar 			ectx.ec_iidx = iptr->isn_arg.forloop.for_end;
10918a7d6542SBram Moolenaar 		    else if (list->lv_first == &range_list_item)
10928a7d6542SBram Moolenaar 		    {
10938a7d6542SBram Moolenaar 			// non-materialized range() list
10948a7d6542SBram Moolenaar 			tv = STACK_TV_BOT(0);
10958a7d6542SBram Moolenaar 			tv->v_type = VAR_NUMBER;
10968a7d6542SBram Moolenaar 			tv->vval.v_number = list_find_nr(
10978a7d6542SBram Moolenaar 					     list, idxtv->vval.v_number, NULL);
10988a7d6542SBram Moolenaar 			++ectx.ec_stack.ga_len;
10998a7d6542SBram Moolenaar 		    }
11008a7d6542SBram Moolenaar 		    else
11018a7d6542SBram Moolenaar 		    {
11028a7d6542SBram Moolenaar 			listitem_T *li = list_find(list, idxtv->vval.v_number);
11038a7d6542SBram Moolenaar 
11048a7d6542SBram Moolenaar 			if (li == NULL)
11058a7d6542SBram Moolenaar 			    goto failed;
11068a7d6542SBram Moolenaar 			copy_tv(&li->li_tv, STACK_TV_BOT(0));
11078a7d6542SBram Moolenaar 			++ectx.ec_stack.ga_len;
11088a7d6542SBram Moolenaar 		    }
11098a7d6542SBram Moolenaar 		}
11108a7d6542SBram Moolenaar 		break;
11118a7d6542SBram Moolenaar 
11128a7d6542SBram Moolenaar 	    // start of ":try" block
11138a7d6542SBram Moolenaar 	    case ISN_TRY:
11148a7d6542SBram Moolenaar 		{
11158a7d6542SBram Moolenaar 		    if (ga_grow(&ectx.ec_trystack, 1) == FAIL)
11168a7d6542SBram Moolenaar 			goto failed;
11178a7d6542SBram Moolenaar 		    trycmd = ((trycmd_T *)ectx.ec_trystack.ga_data)
11188a7d6542SBram Moolenaar 						     + ectx.ec_trystack.ga_len;
11198a7d6542SBram Moolenaar 		    ++ectx.ec_trystack.ga_len;
11208a7d6542SBram Moolenaar 		    ++trylevel;
11218a7d6542SBram Moolenaar 		    trycmd->tcd_frame = ectx.ec_frame;
11228a7d6542SBram Moolenaar 		    trycmd->tcd_catch_idx = iptr->isn_arg.try.try_catch;
11238a7d6542SBram Moolenaar 		    trycmd->tcd_finally_idx = iptr->isn_arg.try.try_finally;
1124f575adffSBram Moolenaar 		    trycmd->tcd_caught = FALSE;
11258a7d6542SBram Moolenaar 		}
11268a7d6542SBram Moolenaar 		break;
11278a7d6542SBram Moolenaar 
11288a7d6542SBram Moolenaar 	    case ISN_PUSHEXC:
11298a7d6542SBram Moolenaar 		if (current_exception == NULL)
11308a7d6542SBram Moolenaar 		{
11318a7d6542SBram Moolenaar 		    iemsg("Evaluating catch while current_exception is NULL");
11328a7d6542SBram Moolenaar 		    goto failed;
11338a7d6542SBram Moolenaar 		}
11348a7d6542SBram Moolenaar 		if (ga_grow(&ectx.ec_stack, 1) == FAIL)
11358a7d6542SBram Moolenaar 		    goto failed;
11368a7d6542SBram Moolenaar 		tv = STACK_TV_BOT(0);
11378a7d6542SBram Moolenaar 		++ectx.ec_stack.ga_len;
11388a7d6542SBram Moolenaar 		tv->v_type = VAR_STRING;
11398a7d6542SBram Moolenaar 		tv->vval.v_string = vim_strsave(
11408a7d6542SBram Moolenaar 					   (char_u *)current_exception->value);
11418a7d6542SBram Moolenaar 		break;
11428a7d6542SBram Moolenaar 
11438a7d6542SBram Moolenaar 	    case ISN_CATCH:
11448a7d6542SBram Moolenaar 		{
11458a7d6542SBram Moolenaar 		    garray_T	*trystack = &ectx.ec_trystack;
11468a7d6542SBram Moolenaar 
11478a7d6542SBram Moolenaar 		    if (trystack->ga_len > 0)
11488a7d6542SBram Moolenaar 		    {
11498a7d6542SBram Moolenaar 			trycmd = ((trycmd_T *)trystack->ga_data)
11508a7d6542SBram Moolenaar 							+ trystack->ga_len - 1;
11518a7d6542SBram Moolenaar 			trycmd->tcd_caught = TRUE;
11528a7d6542SBram Moolenaar 		    }
11538a7d6542SBram Moolenaar 		    did_emsg = got_int = did_throw = FALSE;
11548a7d6542SBram Moolenaar 		    catch_exception(current_exception);
11558a7d6542SBram Moolenaar 		}
11568a7d6542SBram Moolenaar 		break;
11578a7d6542SBram Moolenaar 
11588a7d6542SBram Moolenaar 	    // end of ":try" block
11598a7d6542SBram Moolenaar 	    case ISN_ENDTRY:
11608a7d6542SBram Moolenaar 		{
11618a7d6542SBram Moolenaar 		    garray_T	*trystack = &ectx.ec_trystack;
11628a7d6542SBram Moolenaar 
11638a7d6542SBram Moolenaar 		    if (trystack->ga_len > 0)
11648a7d6542SBram Moolenaar 		    {
11658a7d6542SBram Moolenaar 			--trystack->ga_len;
11668a7d6542SBram Moolenaar 			--trylevel;
11678a7d6542SBram Moolenaar 			trycmd = ((trycmd_T *)trystack->ga_data)
11688a7d6542SBram Moolenaar 							    + trystack->ga_len;
1169f575adffSBram Moolenaar 			if (trycmd->tcd_caught && current_exception != NULL)
11708a7d6542SBram Moolenaar 			{
11718a7d6542SBram Moolenaar 			    // discard the exception
11728a7d6542SBram Moolenaar 			    if (caught_stack == current_exception)
11738a7d6542SBram Moolenaar 				caught_stack = caught_stack->caught;
11748a7d6542SBram Moolenaar 			    discard_current_exception();
11758a7d6542SBram Moolenaar 			}
11768a7d6542SBram Moolenaar 
11778a7d6542SBram Moolenaar 			if (trycmd->tcd_return)
11788a7d6542SBram Moolenaar 			{
11798a7d6542SBram Moolenaar 			    // Restore previous function. If the frame pointer
11808a7d6542SBram Moolenaar 			    // is zero then there is none and we are done.
11818a7d6542SBram Moolenaar 			    if (ectx.ec_frame == initial_frame_ptr)
11828a7d6542SBram Moolenaar 				goto done;
11838a7d6542SBram Moolenaar 
11848a7d6542SBram Moolenaar 			    func_return(&ectx);
11858a7d6542SBram Moolenaar 			}
11868a7d6542SBram Moolenaar 		    }
11878a7d6542SBram Moolenaar 		}
11888a7d6542SBram Moolenaar 		break;
11898a7d6542SBram Moolenaar 
11908a7d6542SBram Moolenaar 	    case ISN_THROW:
11918a7d6542SBram Moolenaar 		--ectx.ec_stack.ga_len;
11928a7d6542SBram Moolenaar 		tv = STACK_TV_BOT(0);
11938a7d6542SBram Moolenaar 		if (throw_exception(tv->vval.v_string, ET_USER, NULL) == FAIL)
11948a7d6542SBram Moolenaar 		{
11958a7d6542SBram Moolenaar 		    vim_free(tv->vval.v_string);
11968a7d6542SBram Moolenaar 		    goto failed;
11978a7d6542SBram Moolenaar 		}
11988a7d6542SBram Moolenaar 		did_throw = TRUE;
11998a7d6542SBram Moolenaar 		break;
12008a7d6542SBram Moolenaar 
12018a7d6542SBram Moolenaar 	    // compare with special values
12028a7d6542SBram Moolenaar 	    case ISN_COMPAREBOOL:
12038a7d6542SBram Moolenaar 	    case ISN_COMPARESPECIAL:
12048a7d6542SBram Moolenaar 		{
12058a7d6542SBram Moolenaar 		    typval_T	*tv1 = STACK_TV_BOT(-2);
12068a7d6542SBram Moolenaar 		    typval_T	*tv2 = STACK_TV_BOT(-1);
12078a7d6542SBram Moolenaar 		    varnumber_T arg1 = tv1->vval.v_number;
12088a7d6542SBram Moolenaar 		    varnumber_T arg2 = tv2->vval.v_number;
12098a7d6542SBram Moolenaar 		    int		res;
12108a7d6542SBram Moolenaar 
12118a7d6542SBram Moolenaar 		    switch (iptr->isn_arg.op.op_type)
12128a7d6542SBram Moolenaar 		    {
12138a7d6542SBram Moolenaar 			case EXPR_EQUAL: res = arg1 == arg2; break;
12148a7d6542SBram Moolenaar 			case EXPR_NEQUAL: res = arg1 != arg2; break;
12158a7d6542SBram Moolenaar 			default: res = 0; break;
12168a7d6542SBram Moolenaar 		    }
12178a7d6542SBram Moolenaar 
12188a7d6542SBram Moolenaar 		    --ectx.ec_stack.ga_len;
12198a7d6542SBram Moolenaar 		    tv1->v_type = VAR_BOOL;
12208a7d6542SBram Moolenaar 		    tv1->vval.v_number = res ? VVAL_TRUE : VVAL_FALSE;
12218a7d6542SBram Moolenaar 		}
12228a7d6542SBram Moolenaar 		break;
12238a7d6542SBram Moolenaar 
12248a7d6542SBram Moolenaar 	    // Operation with two number arguments
12258a7d6542SBram Moolenaar 	    case ISN_OPNR:
12268a7d6542SBram Moolenaar 	    case ISN_COMPARENR:
12278a7d6542SBram Moolenaar 		{
12288a7d6542SBram Moolenaar 		    typval_T	*tv1 = STACK_TV_BOT(-2);
12298a7d6542SBram Moolenaar 		    typval_T	*tv2 = STACK_TV_BOT(-1);
12308a7d6542SBram Moolenaar 		    varnumber_T arg1 = tv1->vval.v_number;
12318a7d6542SBram Moolenaar 		    varnumber_T arg2 = tv2->vval.v_number;
12328a7d6542SBram Moolenaar 		    varnumber_T res;
12338a7d6542SBram Moolenaar 
12348a7d6542SBram Moolenaar 		    switch (iptr->isn_arg.op.op_type)
12358a7d6542SBram Moolenaar 		    {
12368a7d6542SBram Moolenaar 			case EXPR_MULT: res = arg1 * arg2; break;
12378a7d6542SBram Moolenaar 			case EXPR_DIV: res = arg1 / arg2; break;
12388a7d6542SBram Moolenaar 			case EXPR_REM: res = arg1 % arg2; break;
12398a7d6542SBram Moolenaar 			case EXPR_SUB: res = arg1 - arg2; break;
12408a7d6542SBram Moolenaar 			case EXPR_ADD: res = arg1 + arg2; break;
12418a7d6542SBram Moolenaar 
12428a7d6542SBram Moolenaar 			case EXPR_EQUAL: res = arg1 == arg2; break;
12438a7d6542SBram Moolenaar 			case EXPR_NEQUAL: res = arg1 != arg2; break;
12448a7d6542SBram Moolenaar 			case EXPR_GREATER: res = arg1 > arg2; break;
12458a7d6542SBram Moolenaar 			case EXPR_GEQUAL: res = arg1 >= arg2; break;
12468a7d6542SBram Moolenaar 			case EXPR_SMALLER: res = arg1 < arg2; break;
12478a7d6542SBram Moolenaar 			case EXPR_SEQUAL: res = arg1 <= arg2; break;
12488a7d6542SBram Moolenaar 			default: res = 0; break;
12498a7d6542SBram Moolenaar 		    }
12508a7d6542SBram Moolenaar 
12518a7d6542SBram Moolenaar 		    --ectx.ec_stack.ga_len;
12528a7d6542SBram Moolenaar 		    if (iptr->isn_type == ISN_COMPARENR)
12538a7d6542SBram Moolenaar 		    {
12548a7d6542SBram Moolenaar 			tv1->v_type = VAR_BOOL;
12558a7d6542SBram Moolenaar 			tv1->vval.v_number = res ? VVAL_TRUE : VVAL_FALSE;
12568a7d6542SBram Moolenaar 		    }
12578a7d6542SBram Moolenaar 		    else
12588a7d6542SBram Moolenaar 			tv1->vval.v_number = res;
12598a7d6542SBram Moolenaar 		}
12608a7d6542SBram Moolenaar 		break;
12618a7d6542SBram Moolenaar 
12628a7d6542SBram Moolenaar 	    // Computation with two float arguments
12638a7d6542SBram Moolenaar 	    case ISN_OPFLOAT:
12648a7d6542SBram Moolenaar 	    case ISN_COMPAREFLOAT:
1265a5d5953dSBram Moolenaar #ifdef FEAT_FLOAT
12668a7d6542SBram Moolenaar 		{
12678a7d6542SBram Moolenaar 		    typval_T	*tv1 = STACK_TV_BOT(-2);
12688a7d6542SBram Moolenaar 		    typval_T	*tv2 = STACK_TV_BOT(-1);
12698a7d6542SBram Moolenaar 		    float_T	arg1 = tv1->vval.v_float;
12708a7d6542SBram Moolenaar 		    float_T	arg2 = tv2->vval.v_float;
12718a7d6542SBram Moolenaar 		    float_T	res = 0;
12728a7d6542SBram Moolenaar 		    int		cmp = FALSE;
12738a7d6542SBram Moolenaar 
12748a7d6542SBram Moolenaar 		    switch (iptr->isn_arg.op.op_type)
12758a7d6542SBram Moolenaar 		    {
12768a7d6542SBram Moolenaar 			case EXPR_MULT: res = arg1 * arg2; break;
12778a7d6542SBram Moolenaar 			case EXPR_DIV: res = arg1 / arg2; break;
12788a7d6542SBram Moolenaar 			case EXPR_SUB: res = arg1 - arg2; break;
12798a7d6542SBram Moolenaar 			case EXPR_ADD: res = arg1 + arg2; break;
12808a7d6542SBram Moolenaar 
12818a7d6542SBram Moolenaar 			case EXPR_EQUAL: cmp = arg1 == arg2; break;
12828a7d6542SBram Moolenaar 			case EXPR_NEQUAL: cmp = arg1 != arg2; break;
12838a7d6542SBram Moolenaar 			case EXPR_GREATER: cmp = arg1 > arg2; break;
12848a7d6542SBram Moolenaar 			case EXPR_GEQUAL: cmp = arg1 >= arg2; break;
12858a7d6542SBram Moolenaar 			case EXPR_SMALLER: cmp = arg1 < arg2; break;
12868a7d6542SBram Moolenaar 			case EXPR_SEQUAL: cmp = arg1 <= arg2; break;
12878a7d6542SBram Moolenaar 			default: cmp = 0; break;
12888a7d6542SBram Moolenaar 		    }
12898a7d6542SBram Moolenaar 		    --ectx.ec_stack.ga_len;
12908a7d6542SBram Moolenaar 		    if (iptr->isn_type == ISN_COMPAREFLOAT)
12918a7d6542SBram Moolenaar 		    {
12928a7d6542SBram Moolenaar 			tv1->v_type = VAR_BOOL;
12938a7d6542SBram Moolenaar 			tv1->vval.v_number = cmp ? VVAL_TRUE : VVAL_FALSE;
12948a7d6542SBram Moolenaar 		    }
12958a7d6542SBram Moolenaar 		    else
12968a7d6542SBram Moolenaar 			tv1->vval.v_float = res;
12978a7d6542SBram Moolenaar 		}
1298a5d5953dSBram Moolenaar #endif
12998a7d6542SBram Moolenaar 		break;
13008a7d6542SBram Moolenaar 
13018a7d6542SBram Moolenaar 	    case ISN_COMPARELIST:
13028a7d6542SBram Moolenaar 		{
13038a7d6542SBram Moolenaar 		    typval_T	*tv1 = STACK_TV_BOT(-2);
13048a7d6542SBram Moolenaar 		    typval_T	*tv2 = STACK_TV_BOT(-1);
13058a7d6542SBram Moolenaar 		    list_T	*arg1 = tv1->vval.v_list;
13068a7d6542SBram Moolenaar 		    list_T	*arg2 = tv2->vval.v_list;
13078a7d6542SBram Moolenaar 		    int		cmp = FALSE;
13088a7d6542SBram Moolenaar 		    int		ic = iptr->isn_arg.op.op_ic;
13098a7d6542SBram Moolenaar 
13108a7d6542SBram Moolenaar 		    switch (iptr->isn_arg.op.op_type)
13118a7d6542SBram Moolenaar 		    {
13128a7d6542SBram Moolenaar 			case EXPR_EQUAL: cmp =
13138a7d6542SBram Moolenaar 				      list_equal(arg1, arg2, ic, FALSE); break;
13148a7d6542SBram Moolenaar 			case EXPR_NEQUAL: cmp =
13158a7d6542SBram Moolenaar 				     !list_equal(arg1, arg2, ic, FALSE); break;
13168a7d6542SBram Moolenaar 			case EXPR_IS: cmp = arg1 == arg2; break;
13178a7d6542SBram Moolenaar 			case EXPR_ISNOT: cmp = arg1 != arg2; break;
13188a7d6542SBram Moolenaar 			default: cmp = 0; break;
13198a7d6542SBram Moolenaar 		    }
13208a7d6542SBram Moolenaar 		    --ectx.ec_stack.ga_len;
13218a7d6542SBram Moolenaar 		    clear_tv(tv1);
13228a7d6542SBram Moolenaar 		    clear_tv(tv2);
13238a7d6542SBram Moolenaar 		    tv1->v_type = VAR_BOOL;
13248a7d6542SBram Moolenaar 		    tv1->vval.v_number = cmp ? VVAL_TRUE : VVAL_FALSE;
13258a7d6542SBram Moolenaar 		}
13268a7d6542SBram Moolenaar 		break;
13278a7d6542SBram Moolenaar 
13288a7d6542SBram Moolenaar 	    case ISN_COMPAREBLOB:
13298a7d6542SBram Moolenaar 		{
13308a7d6542SBram Moolenaar 		    typval_T	*tv1 = STACK_TV_BOT(-2);
13318a7d6542SBram Moolenaar 		    typval_T	*tv2 = STACK_TV_BOT(-1);
13328a7d6542SBram Moolenaar 		    blob_T	*arg1 = tv1->vval.v_blob;
13338a7d6542SBram Moolenaar 		    blob_T	*arg2 = tv2->vval.v_blob;
13348a7d6542SBram Moolenaar 		    int		cmp = FALSE;
13358a7d6542SBram Moolenaar 
13368a7d6542SBram Moolenaar 		    switch (iptr->isn_arg.op.op_type)
13378a7d6542SBram Moolenaar 		    {
13388a7d6542SBram Moolenaar 			case EXPR_EQUAL: cmp = blob_equal(arg1, arg2); break;
13398a7d6542SBram Moolenaar 			case EXPR_NEQUAL: cmp = !blob_equal(arg1, arg2); break;
13408a7d6542SBram Moolenaar 			case EXPR_IS: cmp = arg1 == arg2; break;
13418a7d6542SBram Moolenaar 			case EXPR_ISNOT: cmp = arg1 != arg2; break;
13428a7d6542SBram Moolenaar 			default: cmp = 0; break;
13438a7d6542SBram Moolenaar 		    }
13448a7d6542SBram Moolenaar 		    --ectx.ec_stack.ga_len;
13458a7d6542SBram Moolenaar 		    clear_tv(tv1);
13468a7d6542SBram Moolenaar 		    clear_tv(tv2);
13478a7d6542SBram Moolenaar 		    tv1->v_type = VAR_BOOL;
13488a7d6542SBram Moolenaar 		    tv1->vval.v_number = cmp ? VVAL_TRUE : VVAL_FALSE;
13498a7d6542SBram Moolenaar 		}
13508a7d6542SBram Moolenaar 		break;
13518a7d6542SBram Moolenaar 
13528a7d6542SBram Moolenaar 		// TODO: handle separately
13538a7d6542SBram Moolenaar 	    case ISN_COMPARESTRING:
13548a7d6542SBram Moolenaar 	    case ISN_COMPAREDICT:
13558a7d6542SBram Moolenaar 	    case ISN_COMPAREFUNC:
13568a7d6542SBram Moolenaar 	    case ISN_COMPAREPARTIAL:
13578a7d6542SBram Moolenaar 	    case ISN_COMPAREANY:
13588a7d6542SBram Moolenaar 		{
13598a7d6542SBram Moolenaar 		    typval_T	*tv1 = STACK_TV_BOT(-2);
13608a7d6542SBram Moolenaar 		    typval_T	*tv2 = STACK_TV_BOT(-1);
13618a7d6542SBram Moolenaar 		    exptype_T	exptype = iptr->isn_arg.op.op_type;
13628a7d6542SBram Moolenaar 		    int		ic = iptr->isn_arg.op.op_ic;
13638a7d6542SBram Moolenaar 
13648a7d6542SBram Moolenaar 		    typval_compare(tv1, tv2, exptype, ic);
13658a7d6542SBram Moolenaar 		    clear_tv(tv2);
13668a7d6542SBram Moolenaar 		    tv1->v_type = VAR_BOOL;
13678a7d6542SBram Moolenaar 		    tv1->vval.v_number = tv1->vval.v_number
13688a7d6542SBram Moolenaar 						      ? VVAL_TRUE : VVAL_FALSE;
13698a7d6542SBram Moolenaar 		    --ectx.ec_stack.ga_len;
13708a7d6542SBram Moolenaar 		}
13718a7d6542SBram Moolenaar 		break;
13728a7d6542SBram Moolenaar 
13738a7d6542SBram Moolenaar 	    case ISN_ADDLIST:
13748a7d6542SBram Moolenaar 	    case ISN_ADDBLOB:
13758a7d6542SBram Moolenaar 		{
13768a7d6542SBram Moolenaar 		    typval_T *tv1 = STACK_TV_BOT(-2);
13778a7d6542SBram Moolenaar 		    typval_T *tv2 = STACK_TV_BOT(-1);
13788a7d6542SBram Moolenaar 
13798a7d6542SBram Moolenaar 		    if (iptr->isn_type == ISN_ADDLIST)
13808a7d6542SBram Moolenaar 			eval_addlist(tv1, tv2);
13818a7d6542SBram Moolenaar 		    else
13828a7d6542SBram Moolenaar 			eval_addblob(tv1, tv2);
13838a7d6542SBram Moolenaar 		    clear_tv(tv2);
13848a7d6542SBram Moolenaar 		    --ectx.ec_stack.ga_len;
13858a7d6542SBram Moolenaar 		}
13868a7d6542SBram Moolenaar 		break;
13878a7d6542SBram Moolenaar 
13888a7d6542SBram Moolenaar 	    // Computation with two arguments of unknown type
13898a7d6542SBram Moolenaar 	    case ISN_OPANY:
13908a7d6542SBram Moolenaar 		{
13918a7d6542SBram Moolenaar 		    typval_T	*tv1 = STACK_TV_BOT(-2);
13928a7d6542SBram Moolenaar 		    typval_T	*tv2 = STACK_TV_BOT(-1);
13938a7d6542SBram Moolenaar 		    varnumber_T	n1, n2;
13948a7d6542SBram Moolenaar #ifdef FEAT_FLOAT
13958a7d6542SBram Moolenaar 		    float_T	f1 = 0, f2 = 0;
13968a7d6542SBram Moolenaar #endif
13978a7d6542SBram Moolenaar 		    int		error = FALSE;
13988a7d6542SBram Moolenaar 
13998a7d6542SBram Moolenaar 		    if (iptr->isn_arg.op.op_type == EXPR_ADD)
14008a7d6542SBram Moolenaar 		    {
14018a7d6542SBram Moolenaar 			if (tv1->v_type == VAR_LIST && tv2->v_type == VAR_LIST)
14028a7d6542SBram Moolenaar 			{
14038a7d6542SBram Moolenaar 			    eval_addlist(tv1, tv2);
14048a7d6542SBram Moolenaar 			    clear_tv(tv2);
14058a7d6542SBram Moolenaar 			    --ectx.ec_stack.ga_len;
14068a7d6542SBram Moolenaar 			    break;
14078a7d6542SBram Moolenaar 			}
14088a7d6542SBram Moolenaar 			else if (tv1->v_type == VAR_BLOB
14098a7d6542SBram Moolenaar 						    && tv2->v_type == VAR_BLOB)
14108a7d6542SBram Moolenaar 			{
14118a7d6542SBram Moolenaar 			    eval_addblob(tv1, tv2);
14128a7d6542SBram Moolenaar 			    clear_tv(tv2);
14138a7d6542SBram Moolenaar 			    --ectx.ec_stack.ga_len;
14148a7d6542SBram Moolenaar 			    break;
14158a7d6542SBram Moolenaar 			}
14168a7d6542SBram Moolenaar 		    }
14178a7d6542SBram Moolenaar #ifdef FEAT_FLOAT
14188a7d6542SBram Moolenaar 		    if (tv1->v_type == VAR_FLOAT)
14198a7d6542SBram Moolenaar 		    {
14208a7d6542SBram Moolenaar 			f1 = tv1->vval.v_float;
14218a7d6542SBram Moolenaar 			n1 = 0;
14228a7d6542SBram Moolenaar 		    }
14238a7d6542SBram Moolenaar 		    else
14248a7d6542SBram Moolenaar #endif
14258a7d6542SBram Moolenaar 		    {
14268a7d6542SBram Moolenaar 			n1 = tv_get_number_chk(tv1, &error);
14278a7d6542SBram Moolenaar 			if (error)
14288a7d6542SBram Moolenaar 			    goto failed;
14298a7d6542SBram Moolenaar #ifdef FEAT_FLOAT
14308a7d6542SBram Moolenaar 			if (tv2->v_type == VAR_FLOAT)
14318a7d6542SBram Moolenaar 			    f1 = n1;
14328a7d6542SBram Moolenaar #endif
14338a7d6542SBram Moolenaar 		    }
14348a7d6542SBram Moolenaar #ifdef FEAT_FLOAT
14358a7d6542SBram Moolenaar 		    if (tv2->v_type == VAR_FLOAT)
14368a7d6542SBram Moolenaar 		    {
14378a7d6542SBram Moolenaar 			f2 = tv2->vval.v_float;
14388a7d6542SBram Moolenaar 			n2 = 0;
14398a7d6542SBram Moolenaar 		    }
14408a7d6542SBram Moolenaar 		    else
14418a7d6542SBram Moolenaar #endif
14428a7d6542SBram Moolenaar 		    {
14438a7d6542SBram Moolenaar 			n2 = tv_get_number_chk(tv2, &error);
14448a7d6542SBram Moolenaar 			if (error)
14458a7d6542SBram Moolenaar 			    goto failed;
14468a7d6542SBram Moolenaar #ifdef FEAT_FLOAT
14478a7d6542SBram Moolenaar 			if (tv1->v_type == VAR_FLOAT)
14488a7d6542SBram Moolenaar 			    f2 = n2;
14498a7d6542SBram Moolenaar #endif
14508a7d6542SBram Moolenaar 		    }
14518a7d6542SBram Moolenaar #ifdef FEAT_FLOAT
14528a7d6542SBram Moolenaar 		    // if there is a float on either side the result is a float
14538a7d6542SBram Moolenaar 		    if (tv1->v_type == VAR_FLOAT || tv2->v_type == VAR_FLOAT)
14548a7d6542SBram Moolenaar 		    {
14558a7d6542SBram Moolenaar 			switch (iptr->isn_arg.op.op_type)
14568a7d6542SBram Moolenaar 			{
14578a7d6542SBram Moolenaar 			    case EXPR_MULT: f1 = f1 * f2; break;
14588a7d6542SBram Moolenaar 			    case EXPR_DIV:  f1 = f1 / f2; break;
14598a7d6542SBram Moolenaar 			    case EXPR_SUB:  f1 = f1 - f2; break;
14608a7d6542SBram Moolenaar 			    case EXPR_ADD:  f1 = f1 + f2; break;
14618a7d6542SBram Moolenaar 			    default: emsg(_(e_modulus)); goto failed;
14628a7d6542SBram Moolenaar 			}
14638a7d6542SBram Moolenaar 			clear_tv(tv1);
14648a7d6542SBram Moolenaar 			clear_tv(tv2);
14658a7d6542SBram Moolenaar 			tv1->v_type = VAR_FLOAT;
14668a7d6542SBram Moolenaar 			tv1->vval.v_float = f1;
14678a7d6542SBram Moolenaar 			--ectx.ec_stack.ga_len;
14688a7d6542SBram Moolenaar 		    }
14698a7d6542SBram Moolenaar 		    else
14708a7d6542SBram Moolenaar #endif
14718a7d6542SBram Moolenaar 		    {
14728a7d6542SBram Moolenaar 			switch (iptr->isn_arg.op.op_type)
14738a7d6542SBram Moolenaar 			{
14748a7d6542SBram Moolenaar 			    case EXPR_MULT: n1 = n1 * n2; break;
14758a7d6542SBram Moolenaar 			    case EXPR_DIV:  n1 = num_divide(n1, n2); break;
14768a7d6542SBram Moolenaar 			    case EXPR_SUB:  n1 = n1 - n2; break;
14778a7d6542SBram Moolenaar 			    case EXPR_ADD:  n1 = n1 + n2; break;
14788a7d6542SBram Moolenaar 			    default:	    n1 = num_modulus(n1, n2); break;
14798a7d6542SBram Moolenaar 			}
14808a7d6542SBram Moolenaar 			clear_tv(tv1);
14818a7d6542SBram Moolenaar 			clear_tv(tv2);
14828a7d6542SBram Moolenaar 			tv1->v_type = VAR_NUMBER;
14838a7d6542SBram Moolenaar 			tv1->vval.v_number = n1;
14848a7d6542SBram Moolenaar 			--ectx.ec_stack.ga_len;
14858a7d6542SBram Moolenaar 		    }
14868a7d6542SBram Moolenaar 		}
14878a7d6542SBram Moolenaar 		break;
14888a7d6542SBram Moolenaar 
14898a7d6542SBram Moolenaar 	    case ISN_CONCAT:
14908a7d6542SBram Moolenaar 		{
14918a7d6542SBram Moolenaar 		    char_u *str1 = STACK_TV_BOT(-2)->vval.v_string;
14928a7d6542SBram Moolenaar 		    char_u *str2 = STACK_TV_BOT(-1)->vval.v_string;
14938a7d6542SBram Moolenaar 		    char_u *res;
14948a7d6542SBram Moolenaar 
14958a7d6542SBram Moolenaar 		    res = concat_str(str1, str2);
14968a7d6542SBram Moolenaar 		    clear_tv(STACK_TV_BOT(-2));
14978a7d6542SBram Moolenaar 		    clear_tv(STACK_TV_BOT(-1));
14988a7d6542SBram Moolenaar 		    --ectx.ec_stack.ga_len;
14998a7d6542SBram Moolenaar 		    STACK_TV_BOT(-1)->vval.v_string = res;
15008a7d6542SBram Moolenaar 		}
15018a7d6542SBram Moolenaar 		break;
15028a7d6542SBram Moolenaar 
15038a7d6542SBram Moolenaar 	    case ISN_INDEX:
15048a7d6542SBram Moolenaar 		{
15058a7d6542SBram Moolenaar 		    list_T	*list;
15068a7d6542SBram Moolenaar 		    varnumber_T	n;
15078a7d6542SBram Moolenaar 		    listitem_T	*li;
15088a7d6542SBram Moolenaar 
15098a7d6542SBram Moolenaar 		    // list index: list is at stack-2, index at stack-1
15108a7d6542SBram Moolenaar 		    tv = STACK_TV_BOT(-2);
15118a7d6542SBram Moolenaar 		    if (tv->v_type != VAR_LIST)
15128a7d6542SBram Moolenaar 		    {
15138a7d6542SBram Moolenaar 			emsg(_(e_listreq));
15148a7d6542SBram Moolenaar 			goto failed;
15158a7d6542SBram Moolenaar 		    }
15168a7d6542SBram Moolenaar 		    list = tv->vval.v_list;
15178a7d6542SBram Moolenaar 
15188a7d6542SBram Moolenaar 		    tv = STACK_TV_BOT(-1);
15198a7d6542SBram Moolenaar 		    if (tv->v_type != VAR_NUMBER)
15208a7d6542SBram Moolenaar 		    {
15218a7d6542SBram Moolenaar 			emsg(_(e_number_exp));
15228a7d6542SBram Moolenaar 			goto failed;
15238a7d6542SBram Moolenaar 		    }
15248a7d6542SBram Moolenaar 		    n = tv->vval.v_number;
15258a7d6542SBram Moolenaar 		    clear_tv(tv);
15268a7d6542SBram Moolenaar 		    if ((li = list_find(list, n)) == NULL)
15278a7d6542SBram Moolenaar 		    {
15288a7d6542SBram Moolenaar 			semsg(_(e_listidx), n);
15298a7d6542SBram Moolenaar 			goto failed;
15308a7d6542SBram Moolenaar 		    }
15318a7d6542SBram Moolenaar 		    --ectx.ec_stack.ga_len;
15328a7d6542SBram Moolenaar 		    clear_tv(STACK_TV_BOT(-1));
15338a7d6542SBram Moolenaar 		    copy_tv(&li->li_tv, STACK_TV_BOT(-1));
15348a7d6542SBram Moolenaar 		}
15358a7d6542SBram Moolenaar 		break;
15368a7d6542SBram Moolenaar 
15378a7d6542SBram Moolenaar 	    // dict member with string key
15388a7d6542SBram Moolenaar 	    case ISN_MEMBER:
15398a7d6542SBram Moolenaar 		{
15408a7d6542SBram Moolenaar 		    dict_T	*dict;
15418a7d6542SBram Moolenaar 		    dictitem_T	*di;
15428a7d6542SBram Moolenaar 
15438a7d6542SBram Moolenaar 		    tv = STACK_TV_BOT(-1);
15448a7d6542SBram Moolenaar 		    if (tv->v_type != VAR_DICT || tv->vval.v_dict == NULL)
15458a7d6542SBram Moolenaar 		    {
15468a7d6542SBram Moolenaar 			emsg(_(e_dictreq));
15478a7d6542SBram Moolenaar 			goto failed;
15488a7d6542SBram Moolenaar 		    }
15498a7d6542SBram Moolenaar 		    dict = tv->vval.v_dict;
15508a7d6542SBram Moolenaar 
15518a7d6542SBram Moolenaar 		    if ((di = dict_find(dict, iptr->isn_arg.string, -1))
15528a7d6542SBram Moolenaar 								       == NULL)
15538a7d6542SBram Moolenaar 		    {
15548a7d6542SBram Moolenaar 			semsg(_(e_dictkey), iptr->isn_arg.string);
15558a7d6542SBram Moolenaar 			goto failed;
15568a7d6542SBram Moolenaar 		    }
15578a7d6542SBram Moolenaar 		    clear_tv(tv);
15588a7d6542SBram Moolenaar 		    copy_tv(&di->di_tv, tv);
15598a7d6542SBram Moolenaar 		}
15608a7d6542SBram Moolenaar 		break;
15618a7d6542SBram Moolenaar 
15628a7d6542SBram Moolenaar 	    case ISN_NEGATENR:
15638a7d6542SBram Moolenaar 		tv = STACK_TV_BOT(-1);
15648a7d6542SBram Moolenaar 		tv->vval.v_number = -tv->vval.v_number;
15658a7d6542SBram Moolenaar 		break;
15668a7d6542SBram Moolenaar 
15678a7d6542SBram Moolenaar 	    case ISN_CHECKNR:
15688a7d6542SBram Moolenaar 		{
15698a7d6542SBram Moolenaar 		    int		error = FALSE;
15708a7d6542SBram Moolenaar 
15718a7d6542SBram Moolenaar 		    tv = STACK_TV_BOT(-1);
15728a7d6542SBram Moolenaar 		    if (check_not_string(tv) == FAIL)
15738a7d6542SBram Moolenaar 			goto failed;
15748a7d6542SBram Moolenaar 		    (void)tv_get_number_chk(tv, &error);
15758a7d6542SBram Moolenaar 		    if (error)
15768a7d6542SBram Moolenaar 			goto failed;
15778a7d6542SBram Moolenaar 		}
15788a7d6542SBram Moolenaar 		break;
15798a7d6542SBram Moolenaar 
15808a7d6542SBram Moolenaar 	    case ISN_CHECKTYPE:
15818a7d6542SBram Moolenaar 		{
15828a7d6542SBram Moolenaar 		    checktype_T *ct = &iptr->isn_arg.type;
15838a7d6542SBram Moolenaar 
15848a7d6542SBram Moolenaar 		    tv = STACK_TV_BOT(ct->ct_off);
15858a7d6542SBram Moolenaar 		    if (tv->v_type != ct->ct_type)
15868a7d6542SBram Moolenaar 		    {
15878a7d6542SBram Moolenaar 			semsg(_("E1029: Expected %s but got %s"),
15888a7d6542SBram Moolenaar 				    vartype_name(ct->ct_type),
15898a7d6542SBram Moolenaar 				    vartype_name(tv->v_type));
15908a7d6542SBram Moolenaar 			goto failed;
15918a7d6542SBram Moolenaar 		    }
15928a7d6542SBram Moolenaar 		}
15938a7d6542SBram Moolenaar 		break;
15948a7d6542SBram Moolenaar 
15958a7d6542SBram Moolenaar 	    case ISN_2BOOL:
15968a7d6542SBram Moolenaar 		{
15978a7d6542SBram Moolenaar 		    int n;
15988a7d6542SBram Moolenaar 
15998a7d6542SBram Moolenaar 		    tv = STACK_TV_BOT(-1);
16008a7d6542SBram Moolenaar 		    n = tv2bool(tv);
16018a7d6542SBram Moolenaar 		    if (iptr->isn_arg.number)  // invert
16028a7d6542SBram Moolenaar 			n = !n;
16038a7d6542SBram Moolenaar 		    clear_tv(tv);
16048a7d6542SBram Moolenaar 		    tv->v_type = VAR_BOOL;
16058a7d6542SBram Moolenaar 		    tv->vval.v_number = n ? VVAL_TRUE : VVAL_FALSE;
16068a7d6542SBram Moolenaar 		}
16078a7d6542SBram Moolenaar 		break;
16088a7d6542SBram Moolenaar 
16098a7d6542SBram Moolenaar 	    case ISN_2STRING:
16108a7d6542SBram Moolenaar 		{
16118a7d6542SBram Moolenaar 		    char_u *str;
16128a7d6542SBram Moolenaar 
16138a7d6542SBram Moolenaar 		    tv = STACK_TV_BOT(iptr->isn_arg.number);
16148a7d6542SBram Moolenaar 		    if (tv->v_type != VAR_STRING)
16158a7d6542SBram Moolenaar 		    {
16168a7d6542SBram Moolenaar 			str = typval_tostring(tv);
16178a7d6542SBram Moolenaar 			clear_tv(tv);
16188a7d6542SBram Moolenaar 			tv->v_type = VAR_STRING;
16198a7d6542SBram Moolenaar 			tv->vval.v_string = str;
16208a7d6542SBram Moolenaar 		    }
16218a7d6542SBram Moolenaar 		}
16228a7d6542SBram Moolenaar 		break;
16238a7d6542SBram Moolenaar 
16248a7d6542SBram Moolenaar 	    case ISN_DROP:
16258a7d6542SBram Moolenaar 		--ectx.ec_stack.ga_len;
16268a7d6542SBram Moolenaar 		clear_tv(STACK_TV_BOT(0));
16278a7d6542SBram Moolenaar 		break;
16288a7d6542SBram Moolenaar 	}
16298a7d6542SBram Moolenaar     }
16308a7d6542SBram Moolenaar 
16318a7d6542SBram Moolenaar done:
16328a7d6542SBram Moolenaar     // function finished, get result from the stack.
16338a7d6542SBram Moolenaar     tv = STACK_TV_BOT(-1);
16348a7d6542SBram Moolenaar     *rettv = *tv;
16358a7d6542SBram Moolenaar     tv->v_type = VAR_UNKNOWN;
16368a7d6542SBram Moolenaar     ret = OK;
16378a7d6542SBram Moolenaar 
16388a7d6542SBram Moolenaar failed:
16397eeefd4aSBram Moolenaar     // When failed need to unwind the call stack.
16407eeefd4aSBram Moolenaar     while (ectx.ec_frame != initial_frame_ptr)
16417eeefd4aSBram Moolenaar 	func_return(&ectx);
16427eeefd4aSBram Moolenaar 
16438a7d6542SBram Moolenaar     for (idx = 0; idx < ectx.ec_stack.ga_len; ++idx)
16448a7d6542SBram Moolenaar 	clear_tv(STACK_TV(idx));
16458a7d6542SBram Moolenaar     vim_free(ectx.ec_stack.ga_data);
16468a7d6542SBram Moolenaar     return ret;
16478a7d6542SBram Moolenaar }
16488a7d6542SBram Moolenaar 
16498a7d6542SBram Moolenaar /*
16508a7d6542SBram Moolenaar  * ":dissassemble".
1651777770fbSBram Moolenaar  * We don't really need this at runtime, but we do have tests that require it,
1652777770fbSBram Moolenaar  * so always include this.
16538a7d6542SBram Moolenaar  */
16548a7d6542SBram Moolenaar     void
16558a7d6542SBram Moolenaar ex_disassemble(exarg_T *eap)
16568a7d6542SBram Moolenaar {
165721456cdcSBram Moolenaar     char_u	*arg = eap->arg;
16580f18b6d1SBram Moolenaar     char_u	*fname;
16590f18b6d1SBram Moolenaar     ufunc_T	*ufunc;
16608a7d6542SBram Moolenaar     dfunc_T	*dfunc;
16618a7d6542SBram Moolenaar     isn_T	*instr;
16628a7d6542SBram Moolenaar     int		current;
16638a7d6542SBram Moolenaar     int		line_idx = 0;
16648a7d6542SBram Moolenaar     int		prev_current = 0;
16658a7d6542SBram Moolenaar 
166621456cdcSBram Moolenaar     fname = trans_function_name(&arg, FALSE,
16670f18b6d1SBram Moolenaar 	     TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL);
166821456cdcSBram Moolenaar     if (fname == NULL)
166921456cdcSBram Moolenaar     {
167021456cdcSBram Moolenaar 	semsg(_(e_invarg2), eap->arg);
167121456cdcSBram Moolenaar 	return;
167221456cdcSBram Moolenaar     }
167321456cdcSBram Moolenaar 
16740f18b6d1SBram Moolenaar     ufunc = find_func(fname, NULL);
16750f18b6d1SBram Moolenaar     vim_free(fname);
16768a7d6542SBram Moolenaar     if (ufunc == NULL)
16778a7d6542SBram Moolenaar     {
1678df2ecddfSBram Moolenaar 	semsg(_("E1061: Cannot find function %s"), eap->arg);
16798a7d6542SBram Moolenaar 	return;
16808a7d6542SBram Moolenaar     }
16818a7d6542SBram Moolenaar     if (ufunc->uf_dfunc_idx < 0)
16828a7d6542SBram Moolenaar     {
1683df2ecddfSBram Moolenaar 	semsg(_("E1062: Function %s is not compiled"), eap->arg);
16848a7d6542SBram Moolenaar 	return;
16858a7d6542SBram Moolenaar     }
16868a7d6542SBram Moolenaar     if (ufunc->uf_name_exp != NULL)
16878a7d6542SBram Moolenaar 	msg((char *)ufunc->uf_name_exp);
16888a7d6542SBram Moolenaar     else
16898a7d6542SBram Moolenaar 	msg((char *)ufunc->uf_name);
16908a7d6542SBram Moolenaar 
16918a7d6542SBram Moolenaar     dfunc = ((dfunc_T *)def_functions.ga_data) + ufunc->uf_dfunc_idx;
16928a7d6542SBram Moolenaar     instr = dfunc->df_instr;
16938a7d6542SBram Moolenaar     for (current = 0; current < dfunc->df_instr_count; ++current)
16948a7d6542SBram Moolenaar     {
16958a7d6542SBram Moolenaar 	isn_T	    *iptr = &instr[current];
1696f2460a3aSBram Moolenaar 	char	    *line;
16978a7d6542SBram Moolenaar 
16988a7d6542SBram Moolenaar 	while (line_idx < iptr->isn_lnum && line_idx < ufunc->uf_lines.ga_len)
16998a7d6542SBram Moolenaar 	{
17008a7d6542SBram Moolenaar 	    if (current > prev_current)
17018a7d6542SBram Moolenaar 	    {
17028a7d6542SBram Moolenaar 		msg_puts("\n\n");
17038a7d6542SBram Moolenaar 		prev_current = current;
17048a7d6542SBram Moolenaar 	    }
1705f2460a3aSBram Moolenaar 	    line = ((char **)ufunc->uf_lines.ga_data)[line_idx++];
1706f2460a3aSBram Moolenaar 	    if (line != NULL)
1707f2460a3aSBram Moolenaar 		msg(line);
17088a7d6542SBram Moolenaar 	}
17098a7d6542SBram Moolenaar 
17108a7d6542SBram Moolenaar 	switch (iptr->isn_type)
17118a7d6542SBram Moolenaar 	{
17128a7d6542SBram Moolenaar 	    case ISN_EXEC:
17138a7d6542SBram Moolenaar 		smsg("%4d EXEC %s", current, iptr->isn_arg.string);
17148a7d6542SBram Moolenaar 		break;
17158a7d6542SBram Moolenaar 	    case ISN_ECHO:
17168a7d6542SBram Moolenaar 		{
17178a7d6542SBram Moolenaar 		    echo_T *echo = &iptr->isn_arg.echo;
17188a7d6542SBram Moolenaar 
17198a7d6542SBram Moolenaar 		    smsg("%4d %s %d", current,
17208a7d6542SBram Moolenaar 			    echo->echo_with_white ? "ECHO" : "ECHON",
17218a7d6542SBram Moolenaar 			    echo->echo_count);
17228a7d6542SBram Moolenaar 		}
17238a7d6542SBram Moolenaar 		break;
1724ad39c094SBram Moolenaar 	    case ISN_EXECUTE:
1725ad39c094SBram Moolenaar 		smsg("%4d EXECUTE %d", current, iptr->isn_arg.number);
1726ad39c094SBram Moolenaar 		break;
17278a7d6542SBram Moolenaar 	    case ISN_LOAD:
17288a7d6542SBram Moolenaar 		if (iptr->isn_arg.number < 0)
17298a7d6542SBram Moolenaar 		    smsg("%4d LOAD arg[%lld]", current,
17308a7d6542SBram Moolenaar 				      iptr->isn_arg.number + STACK_FRAME_SIZE);
17318a7d6542SBram Moolenaar 		else
17328a7d6542SBram Moolenaar 		    smsg("%4d LOAD $%lld", current, iptr->isn_arg.number);
17338a7d6542SBram Moolenaar 		break;
17348a7d6542SBram Moolenaar 	    case ISN_LOADV:
17358a7d6542SBram Moolenaar 		smsg("%4d LOADV v:%s", current,
17368a7d6542SBram Moolenaar 				       get_vim_var_name(iptr->isn_arg.number));
17378a7d6542SBram Moolenaar 		break;
17388a7d6542SBram Moolenaar 	    case ISN_LOADSCRIPT:
17398a7d6542SBram Moolenaar 		{
17408a7d6542SBram Moolenaar 		    scriptitem_T *si =
174121b9e977SBram Moolenaar 				  SCRIPT_ITEM(iptr->isn_arg.script.script_sid);
17428a7d6542SBram Moolenaar 		    svar_T *sv = ((svar_T *)si->sn_var_vals.ga_data)
17438a7d6542SBram Moolenaar 					     + iptr->isn_arg.script.script_idx;
17448a7d6542SBram Moolenaar 
17458a7d6542SBram Moolenaar 		    smsg("%4d LOADSCRIPT %s from %s", current,
17468a7d6542SBram Moolenaar 						     sv->sv_name, si->sn_name);
17478a7d6542SBram Moolenaar 		}
17488a7d6542SBram Moolenaar 		break;
17498a7d6542SBram Moolenaar 	    case ISN_LOADS:
17508a7d6542SBram Moolenaar 		{
1751b283a8a6SBram Moolenaar 		    scriptitem_T *si = SCRIPT_ITEM(
1752b283a8a6SBram Moolenaar 					       iptr->isn_arg.loadstore.ls_sid);
17538a7d6542SBram Moolenaar 
17548a7d6542SBram Moolenaar 		    smsg("%4d LOADS s:%s from %s", current,
17558a7d6542SBram Moolenaar 					    iptr->isn_arg.string, si->sn_name);
17568a7d6542SBram Moolenaar 		}
17578a7d6542SBram Moolenaar 		break;
17588a7d6542SBram Moolenaar 	    case ISN_LOADG:
17598a7d6542SBram Moolenaar 		smsg("%4d LOADG g:%s", current, iptr->isn_arg.string);
17608a7d6542SBram Moolenaar 		break;
17618a7d6542SBram Moolenaar 	    case ISN_LOADOPT:
17628a7d6542SBram Moolenaar 		smsg("%4d LOADOPT %s", current, iptr->isn_arg.string);
17638a7d6542SBram Moolenaar 		break;
17648a7d6542SBram Moolenaar 	    case ISN_LOADENV:
17658a7d6542SBram Moolenaar 		smsg("%4d LOADENV %s", current, iptr->isn_arg.string);
17668a7d6542SBram Moolenaar 		break;
17678a7d6542SBram Moolenaar 	    case ISN_LOADREG:
17688a7d6542SBram Moolenaar 		smsg("%4d LOADREG @%c", current, iptr->isn_arg.number);
17698a7d6542SBram Moolenaar 		break;
17708a7d6542SBram Moolenaar 
17718a7d6542SBram Moolenaar 	    case ISN_STORE:
1772170fcfcfSBram Moolenaar 		if (iptr->isn_arg.number < 0)
1773170fcfcfSBram Moolenaar 		    smsg("%4d STORE arg[%lld]", current,
1774170fcfcfSBram Moolenaar 				      iptr->isn_arg.number + STACK_FRAME_SIZE);
1775170fcfcfSBram Moolenaar 		else
17768a7d6542SBram Moolenaar 		    smsg("%4d STORE $%lld", current, iptr->isn_arg.number);
17778a7d6542SBram Moolenaar 		break;
1778b283a8a6SBram Moolenaar 	    case ISN_STOREV:
1779b283a8a6SBram Moolenaar 		smsg("%4d STOREV v:%s", current,
1780b283a8a6SBram Moolenaar 				       get_vim_var_name(iptr->isn_arg.number));
1781b283a8a6SBram Moolenaar 		break;
17828a7d6542SBram Moolenaar 	    case ISN_STOREG:
1783b283a8a6SBram Moolenaar 		smsg("%4d STOREG %s", current, iptr->isn_arg.string);
1784b283a8a6SBram Moolenaar 		break;
1785b283a8a6SBram Moolenaar 	    case ISN_STORES:
1786b283a8a6SBram Moolenaar 		{
1787b283a8a6SBram Moolenaar 		    scriptitem_T *si = SCRIPT_ITEM(
1788b283a8a6SBram Moolenaar 					       iptr->isn_arg.loadstore.ls_sid);
1789b283a8a6SBram Moolenaar 
17900bbf722aSBram Moolenaar 		    smsg("%4d STORES %s in %s", current,
1791b283a8a6SBram Moolenaar 					    iptr->isn_arg.string, si->sn_name);
1792b283a8a6SBram Moolenaar 		}
17938a7d6542SBram Moolenaar 		break;
17948a7d6542SBram Moolenaar 	    case ISN_STORESCRIPT:
17958a7d6542SBram Moolenaar 		{
17968a7d6542SBram Moolenaar 		    scriptitem_T *si =
179721b9e977SBram Moolenaar 				  SCRIPT_ITEM(iptr->isn_arg.script.script_sid);
17988a7d6542SBram Moolenaar 		    svar_T *sv = ((svar_T *)si->sn_var_vals.ga_data)
17998a7d6542SBram Moolenaar 					     + iptr->isn_arg.script.script_idx;
18008a7d6542SBram Moolenaar 
18018a7d6542SBram Moolenaar 		    smsg("%4d STORESCRIPT %s in %s", current,
18028a7d6542SBram Moolenaar 						     sv->sv_name, si->sn_name);
18038a7d6542SBram Moolenaar 		}
18048a7d6542SBram Moolenaar 		break;
18058a7d6542SBram Moolenaar 	    case ISN_STOREOPT:
18068a7d6542SBram Moolenaar 		smsg("%4d STOREOPT &%s", current,
18078a7d6542SBram Moolenaar 					       iptr->isn_arg.storeopt.so_name);
18088a7d6542SBram Moolenaar 		break;
1809b283a8a6SBram Moolenaar 	    case ISN_STOREENV:
1810b283a8a6SBram Moolenaar 		smsg("%4d STOREENV $%s", current, iptr->isn_arg.string);
1811b283a8a6SBram Moolenaar 		break;
1812b283a8a6SBram Moolenaar 	    case ISN_STOREREG:
1813b283a8a6SBram Moolenaar 		smsg("%4d STOREREG @%c", current, iptr->isn_arg.number);
1814b283a8a6SBram Moolenaar 		break;
18158a7d6542SBram Moolenaar 	    case ISN_STORENR:
18168a7d6542SBram Moolenaar 		smsg("%4d STORE %lld in $%d", current,
18178a7d6542SBram Moolenaar 				iptr->isn_arg.storenr.str_val,
18188a7d6542SBram Moolenaar 				iptr->isn_arg.storenr.str_idx);
18198a7d6542SBram Moolenaar 		break;
18208a7d6542SBram Moolenaar 
18218a7d6542SBram Moolenaar 	    // constants
18228a7d6542SBram Moolenaar 	    case ISN_PUSHNR:
18238a7d6542SBram Moolenaar 		smsg("%4d PUSHNR %lld", current, iptr->isn_arg.number);
18248a7d6542SBram Moolenaar 		break;
18258a7d6542SBram Moolenaar 	    case ISN_PUSHBOOL:
18268a7d6542SBram Moolenaar 	    case ISN_PUSHSPEC:
18278a7d6542SBram Moolenaar 		smsg("%4d PUSH %s", current,
18288a7d6542SBram Moolenaar 				   get_var_special_name(iptr->isn_arg.number));
18298a7d6542SBram Moolenaar 		break;
18308a7d6542SBram Moolenaar 	    case ISN_PUSHF:
1831a5d5953dSBram Moolenaar #ifdef FEAT_FLOAT
18328a7d6542SBram Moolenaar 		smsg("%4d PUSHF %g", current, iptr->isn_arg.fnumber);
1833a5d5953dSBram Moolenaar #endif
18348a7d6542SBram Moolenaar 		break;
18358a7d6542SBram Moolenaar 	    case ISN_PUSHS:
18368a7d6542SBram Moolenaar 		smsg("%4d PUSHS \"%s\"", current, iptr->isn_arg.string);
18378a7d6542SBram Moolenaar 		break;
18388a7d6542SBram Moolenaar 	    case ISN_PUSHBLOB:
18398a7d6542SBram Moolenaar 		{
18408a7d6542SBram Moolenaar 		    char_u	*r;
18418a7d6542SBram Moolenaar 		    char_u	numbuf[NUMBUFLEN];
18428a7d6542SBram Moolenaar 		    char_u	*tofree;
18438a7d6542SBram Moolenaar 
18448a7d6542SBram Moolenaar 		    r = blob2string(iptr->isn_arg.blob, &tofree, numbuf);
1845ff80cb68SBram Moolenaar 		    smsg("%4d PUSHBLOB %s", current, r);
18468a7d6542SBram Moolenaar 		    vim_free(tofree);
18478a7d6542SBram Moolenaar 		}
18488a7d6542SBram Moolenaar 		break;
18498a7d6542SBram Moolenaar 	    case ISN_PUSHEXC:
18508a7d6542SBram Moolenaar 		smsg("%4d PUSH v:exception", current);
18518a7d6542SBram Moolenaar 		break;
18528a7d6542SBram Moolenaar 	    case ISN_NEWLIST:
18538a7d6542SBram Moolenaar 		smsg("%4d NEWLIST size %lld", current, iptr->isn_arg.number);
18548a7d6542SBram Moolenaar 		break;
18558a7d6542SBram Moolenaar 	    case ISN_NEWDICT:
18568a7d6542SBram Moolenaar 		smsg("%4d NEWDICT size %lld", current, iptr->isn_arg.number);
18578a7d6542SBram Moolenaar 		break;
18588a7d6542SBram Moolenaar 
18598a7d6542SBram Moolenaar 	    // function call
18608a7d6542SBram Moolenaar 	    case ISN_BCALL:
18618a7d6542SBram Moolenaar 		{
18628a7d6542SBram Moolenaar 		    cbfunc_T	*cbfunc = &iptr->isn_arg.bfunc;
18638a7d6542SBram Moolenaar 
18648a7d6542SBram Moolenaar 		    smsg("%4d BCALL %s(argc %d)", current,
18658a7d6542SBram Moolenaar 			    internal_func_name(cbfunc->cbf_idx),
18668a7d6542SBram Moolenaar 			    cbfunc->cbf_argcount);
18678a7d6542SBram Moolenaar 		}
18688a7d6542SBram Moolenaar 		break;
18698a7d6542SBram Moolenaar 	    case ISN_DCALL:
18708a7d6542SBram Moolenaar 		{
18718a7d6542SBram Moolenaar 		    cdfunc_T	*cdfunc = &iptr->isn_arg.dfunc;
18728a7d6542SBram Moolenaar 		    dfunc_T	*df = ((dfunc_T *)def_functions.ga_data)
18738a7d6542SBram Moolenaar 							     + cdfunc->cdf_idx;
18748a7d6542SBram Moolenaar 
18758a7d6542SBram Moolenaar 		    smsg("%4d DCALL %s(argc %d)", current,
18768a7d6542SBram Moolenaar 			    df->df_ufunc->uf_name_exp != NULL
18778a7d6542SBram Moolenaar 				? df->df_ufunc->uf_name_exp
18788a7d6542SBram Moolenaar 				: df->df_ufunc->uf_name, cdfunc->cdf_argcount);
18798a7d6542SBram Moolenaar 		}
18808a7d6542SBram Moolenaar 		break;
18818a7d6542SBram Moolenaar 	    case ISN_UCALL:
18828a7d6542SBram Moolenaar 		{
18838a7d6542SBram Moolenaar 		    cufunc_T	*cufunc = &iptr->isn_arg.ufunc;
18848a7d6542SBram Moolenaar 
18858a7d6542SBram Moolenaar 		    smsg("%4d UCALL %s(argc %d)", current,
18868a7d6542SBram Moolenaar 				       cufunc->cuf_name, cufunc->cuf_argcount);
18878a7d6542SBram Moolenaar 		}
18888a7d6542SBram Moolenaar 		break;
18898a7d6542SBram Moolenaar 	    case ISN_PCALL:
18908a7d6542SBram Moolenaar 		{
18918a7d6542SBram Moolenaar 		    cpfunc_T	*cpfunc = &iptr->isn_arg.pfunc;
18928a7d6542SBram Moolenaar 
18938a7d6542SBram Moolenaar 		    smsg("%4d PCALL%s (argc %d)", current,
18948a7d6542SBram Moolenaar 			   cpfunc->cpf_top ? " top" : "", cpfunc->cpf_argcount);
18958a7d6542SBram Moolenaar 		}
18968a7d6542SBram Moolenaar 		break;
18978a7d6542SBram Moolenaar 	    case ISN_RETURN:
18988a7d6542SBram Moolenaar 		smsg("%4d RETURN", current);
18998a7d6542SBram Moolenaar 		break;
19008a7d6542SBram Moolenaar 	    case ISN_FUNCREF:
19018a7d6542SBram Moolenaar 		{
19028a7d6542SBram Moolenaar 		    dfunc_T	*df = ((dfunc_T *)def_functions.ga_data)
19038a7d6542SBram Moolenaar 							+ iptr->isn_arg.number;
19048a7d6542SBram Moolenaar 
19058a7d6542SBram Moolenaar 		    smsg("%4d FUNCREF %s", current, df->df_ufunc->uf_name);
19068a7d6542SBram Moolenaar 		}
19078a7d6542SBram Moolenaar 		break;
19088a7d6542SBram Moolenaar 
19098a7d6542SBram Moolenaar 	    case ISN_JUMP:
19108a7d6542SBram Moolenaar 		{
19118a7d6542SBram Moolenaar 		    char *when = "?";
19128a7d6542SBram Moolenaar 
19138a7d6542SBram Moolenaar 		    switch (iptr->isn_arg.jump.jump_when)
19148a7d6542SBram Moolenaar 		    {
19158a7d6542SBram Moolenaar 			case JUMP_ALWAYS:
19168a7d6542SBram Moolenaar 			    when = "JUMP";
19178a7d6542SBram Moolenaar 			    break;
19188a7d6542SBram Moolenaar 			case JUMP_AND_KEEP_IF_TRUE:
19198a7d6542SBram Moolenaar 			    when = "JUMP_AND_KEEP_IF_TRUE";
19208a7d6542SBram Moolenaar 			    break;
19218a7d6542SBram Moolenaar 			case JUMP_IF_FALSE:
19228a7d6542SBram Moolenaar 			    when = "JUMP_IF_FALSE";
19238a7d6542SBram Moolenaar 			    break;
19248a7d6542SBram Moolenaar 			case JUMP_AND_KEEP_IF_FALSE:
19258a7d6542SBram Moolenaar 			    when = "JUMP_AND_KEEP_IF_FALSE";
19268a7d6542SBram Moolenaar 			    break;
19278a7d6542SBram Moolenaar 		    }
19288a7d6542SBram Moolenaar 		    smsg("%4d %s -> %lld", current, when,
19298a7d6542SBram Moolenaar 						iptr->isn_arg.jump.jump_where);
19308a7d6542SBram Moolenaar 		}
19318a7d6542SBram Moolenaar 		break;
19328a7d6542SBram Moolenaar 
19338a7d6542SBram Moolenaar 	    case ISN_FOR:
19348a7d6542SBram Moolenaar 		{
19358a7d6542SBram Moolenaar 		    forloop_T *forloop = &iptr->isn_arg.forloop;
19368a7d6542SBram Moolenaar 
19378a7d6542SBram Moolenaar 		    smsg("%4d FOR $%d -> %d", current,
19388a7d6542SBram Moolenaar 					   forloop->for_idx, forloop->for_end);
19398a7d6542SBram Moolenaar 		}
19408a7d6542SBram Moolenaar 		break;
19418a7d6542SBram Moolenaar 
19428a7d6542SBram Moolenaar 	    case ISN_TRY:
19438a7d6542SBram Moolenaar 		{
19448a7d6542SBram Moolenaar 		    try_T *try = &iptr->isn_arg.try;
19458a7d6542SBram Moolenaar 
19468a7d6542SBram Moolenaar 		    smsg("%4d TRY catch -> %d, finally -> %d", current,
19478a7d6542SBram Moolenaar 					     try->try_catch, try->try_finally);
19488a7d6542SBram Moolenaar 		}
19498a7d6542SBram Moolenaar 		break;
19508a7d6542SBram Moolenaar 	    case ISN_CATCH:
19518a7d6542SBram Moolenaar 		// TODO
19528a7d6542SBram Moolenaar 		smsg("%4d CATCH", current);
19538a7d6542SBram Moolenaar 		break;
19548a7d6542SBram Moolenaar 	    case ISN_ENDTRY:
19558a7d6542SBram Moolenaar 		smsg("%4d ENDTRY", current);
19568a7d6542SBram Moolenaar 		break;
19578a7d6542SBram Moolenaar 	    case ISN_THROW:
19588a7d6542SBram Moolenaar 		smsg("%4d THROW", current);
19598a7d6542SBram Moolenaar 		break;
19608a7d6542SBram Moolenaar 
19618a7d6542SBram Moolenaar 	    // expression operations on number
19628a7d6542SBram Moolenaar 	    case ISN_OPNR:
19638a7d6542SBram Moolenaar 	    case ISN_OPFLOAT:
19648a7d6542SBram Moolenaar 	    case ISN_OPANY:
19658a7d6542SBram Moolenaar 		{
19668a7d6542SBram Moolenaar 		    char *what;
19678a7d6542SBram Moolenaar 		    char *ins;
19688a7d6542SBram Moolenaar 
19698a7d6542SBram Moolenaar 		    switch (iptr->isn_arg.op.op_type)
19708a7d6542SBram Moolenaar 		    {
19718a7d6542SBram Moolenaar 			case EXPR_MULT: what = "*"; break;
19728a7d6542SBram Moolenaar 			case EXPR_DIV: what = "/"; break;
19738a7d6542SBram Moolenaar 			case EXPR_REM: what = "%"; break;
19748a7d6542SBram Moolenaar 			case EXPR_SUB: what = "-"; break;
19758a7d6542SBram Moolenaar 			case EXPR_ADD: what = "+"; break;
19768a7d6542SBram Moolenaar 			default:       what = "???"; break;
19778a7d6542SBram Moolenaar 		    }
19788a7d6542SBram Moolenaar 		    switch (iptr->isn_type)
19798a7d6542SBram Moolenaar 		    {
19808a7d6542SBram Moolenaar 			case ISN_OPNR: ins = "OPNR"; break;
19818a7d6542SBram Moolenaar 			case ISN_OPFLOAT: ins = "OPFLOAT"; break;
19828a7d6542SBram Moolenaar 			case ISN_OPANY: ins = "OPANY"; break;
19838a7d6542SBram Moolenaar 			default: ins = "???"; break;
19848a7d6542SBram Moolenaar 		    }
19858a7d6542SBram Moolenaar 		    smsg("%4d %s %s", current, ins, what);
19868a7d6542SBram Moolenaar 		}
19878a7d6542SBram Moolenaar 		break;
19888a7d6542SBram Moolenaar 
19898a7d6542SBram Moolenaar 	    case ISN_COMPAREBOOL:
19908a7d6542SBram Moolenaar 	    case ISN_COMPARESPECIAL:
19918a7d6542SBram Moolenaar 	    case ISN_COMPARENR:
19928a7d6542SBram Moolenaar 	    case ISN_COMPAREFLOAT:
19938a7d6542SBram Moolenaar 	    case ISN_COMPARESTRING:
19948a7d6542SBram Moolenaar 	    case ISN_COMPAREBLOB:
19958a7d6542SBram Moolenaar 	    case ISN_COMPARELIST:
19968a7d6542SBram Moolenaar 	    case ISN_COMPAREDICT:
19978a7d6542SBram Moolenaar 	    case ISN_COMPAREFUNC:
19988a7d6542SBram Moolenaar 	    case ISN_COMPAREPARTIAL:
19998a7d6542SBram Moolenaar 	    case ISN_COMPAREANY:
20008a7d6542SBram Moolenaar 		   {
20018a7d6542SBram Moolenaar 		       char *p;
20028a7d6542SBram Moolenaar 		       char buf[10];
20038a7d6542SBram Moolenaar 		       char *type;
20048a7d6542SBram Moolenaar 
20058a7d6542SBram Moolenaar 		       switch (iptr->isn_arg.op.op_type)
20068a7d6542SBram Moolenaar 		       {
20078a7d6542SBram Moolenaar 			   case EXPR_EQUAL:	 p = "=="; break;
20088a7d6542SBram Moolenaar 			   case EXPR_NEQUAL:    p = "!="; break;
20098a7d6542SBram Moolenaar 			   case EXPR_GREATER:   p = ">"; break;
20108a7d6542SBram Moolenaar 			   case EXPR_GEQUAL:    p = ">="; break;
20118a7d6542SBram Moolenaar 			   case EXPR_SMALLER:   p = "<"; break;
20128a7d6542SBram Moolenaar 			   case EXPR_SEQUAL:    p = "<="; break;
20138a7d6542SBram Moolenaar 			   case EXPR_MATCH:	 p = "=~"; break;
20148a7d6542SBram Moolenaar 			   case EXPR_IS:	 p = "is"; break;
20158a7d6542SBram Moolenaar 			   case EXPR_ISNOT:	 p = "isnot"; break;
20168a7d6542SBram Moolenaar 			   case EXPR_NOMATCH:	 p = "!~"; break;
20178a7d6542SBram Moolenaar 			   default:  p = "???"; break;
20188a7d6542SBram Moolenaar 		       }
20198a7d6542SBram Moolenaar 		       STRCPY(buf, p);
20208a7d6542SBram Moolenaar 		       if (iptr->isn_arg.op.op_ic == TRUE)
20218a7d6542SBram Moolenaar 			   strcat(buf, "?");
20228a7d6542SBram Moolenaar 		       switch(iptr->isn_type)
20238a7d6542SBram Moolenaar 		       {
20248a7d6542SBram Moolenaar 			   case ISN_COMPAREBOOL: type = "COMPAREBOOL"; break;
20258a7d6542SBram Moolenaar 			   case ISN_COMPARESPECIAL:
20268a7d6542SBram Moolenaar 						 type = "COMPARESPECIAL"; break;
20278a7d6542SBram Moolenaar 			   case ISN_COMPARENR: type = "COMPARENR"; break;
20288a7d6542SBram Moolenaar 			   case ISN_COMPAREFLOAT: type = "COMPAREFLOAT"; break;
20298a7d6542SBram Moolenaar 			   case ISN_COMPARESTRING:
20308a7d6542SBram Moolenaar 						  type = "COMPARESTRING"; break;
20318a7d6542SBram Moolenaar 			   case ISN_COMPAREBLOB: type = "COMPAREBLOB"; break;
20328a7d6542SBram Moolenaar 			   case ISN_COMPARELIST: type = "COMPARELIST"; break;
20338a7d6542SBram Moolenaar 			   case ISN_COMPAREDICT: type = "COMPAREDICT"; break;
20348a7d6542SBram Moolenaar 			   case ISN_COMPAREFUNC: type = "COMPAREFUNC"; break;
20358a7d6542SBram Moolenaar 			   case ISN_COMPAREPARTIAL:
20368a7d6542SBram Moolenaar 						 type = "COMPAREPARTIAL"; break;
20378a7d6542SBram Moolenaar 			   case ISN_COMPAREANY: type = "COMPAREANY"; break;
20388a7d6542SBram Moolenaar 			   default: type = "???"; break;
20398a7d6542SBram Moolenaar 		       }
20408a7d6542SBram Moolenaar 
20418a7d6542SBram Moolenaar 		       smsg("%4d %s %s", current, type, buf);
20428a7d6542SBram Moolenaar 		   }
20438a7d6542SBram Moolenaar 		   break;
20448a7d6542SBram Moolenaar 
20458a7d6542SBram Moolenaar 	    case ISN_ADDLIST: smsg("%4d ADDLIST", current); break;
20468a7d6542SBram Moolenaar 	    case ISN_ADDBLOB: smsg("%4d ADDBLOB", current); break;
20478a7d6542SBram Moolenaar 
20488a7d6542SBram Moolenaar 	    // expression operations
20498a7d6542SBram Moolenaar 	    case ISN_CONCAT: smsg("%4d CONCAT", current); break;
20508a7d6542SBram Moolenaar 	    case ISN_INDEX: smsg("%4d INDEX", current); break;
20518a7d6542SBram Moolenaar 	    case ISN_MEMBER: smsg("%4d MEMBER %s", current,
20528a7d6542SBram Moolenaar 						  iptr->isn_arg.string); break;
20538a7d6542SBram Moolenaar 	    case ISN_NEGATENR: smsg("%4d NEGATENR", current); break;
20548a7d6542SBram Moolenaar 
20558a7d6542SBram Moolenaar 	    case ISN_CHECKNR: smsg("%4d CHECKNR", current); break;
20568a7d6542SBram Moolenaar 	    case ISN_CHECKTYPE: smsg("%4d CHECKTYPE %s stack[%d]", current,
20578a7d6542SBram Moolenaar 				      vartype_name(iptr->isn_arg.type.ct_type),
20588a7d6542SBram Moolenaar 				      iptr->isn_arg.type.ct_off);
20598a7d6542SBram Moolenaar 				break;
20608a7d6542SBram Moolenaar 	    case ISN_2BOOL: if (iptr->isn_arg.number)
20618a7d6542SBram Moolenaar 				smsg("%4d INVERT (!val)", current);
20628a7d6542SBram Moolenaar 			    else
20638a7d6542SBram Moolenaar 				smsg("%4d 2BOOL (!!val)", current);
20648a7d6542SBram Moolenaar 			    break;
20658a7d6542SBram Moolenaar 	    case ISN_2STRING: smsg("%4d 2STRING stack[%d]", current,
20668a7d6542SBram Moolenaar 							 iptr->isn_arg.number);
20678a7d6542SBram Moolenaar 				break;
20688a7d6542SBram Moolenaar 
20698a7d6542SBram Moolenaar 	    case ISN_DROP: smsg("%4d DROP", current); break;
20708a7d6542SBram Moolenaar 	}
20718a7d6542SBram Moolenaar     }
20728a7d6542SBram Moolenaar }
20738a7d6542SBram Moolenaar 
20748a7d6542SBram Moolenaar /*
20758a7d6542SBram Moolenaar  * Return TRUE when "tv" is not falsey: non-zero, non-empty string, non-empty
20768a7d6542SBram Moolenaar  * list, etc.  Mostly like what JavaScript does, except that empty list and
20778a7d6542SBram Moolenaar  * empty dictionary are FALSE.
20788a7d6542SBram Moolenaar  */
20798a7d6542SBram Moolenaar     int
20808a7d6542SBram Moolenaar tv2bool(typval_T *tv)
20818a7d6542SBram Moolenaar {
20828a7d6542SBram Moolenaar     switch (tv->v_type)
20838a7d6542SBram Moolenaar     {
20848a7d6542SBram Moolenaar 	case VAR_NUMBER:
20858a7d6542SBram Moolenaar 	    return tv->vval.v_number != 0;
20868a7d6542SBram Moolenaar 	case VAR_FLOAT:
20878a7d6542SBram Moolenaar #ifdef FEAT_FLOAT
20888a7d6542SBram Moolenaar 	    return tv->vval.v_float != 0.0;
20898a7d6542SBram Moolenaar #else
20908a7d6542SBram Moolenaar 	    break;
20918a7d6542SBram Moolenaar #endif
20928a7d6542SBram Moolenaar 	case VAR_PARTIAL:
20938a7d6542SBram Moolenaar 	    return tv->vval.v_partial != NULL;
20948a7d6542SBram Moolenaar 	case VAR_FUNC:
20958a7d6542SBram Moolenaar 	case VAR_STRING:
20968a7d6542SBram Moolenaar 	    return tv->vval.v_string != NULL && *tv->vval.v_string != NUL;
20978a7d6542SBram Moolenaar 	case VAR_LIST:
20988a7d6542SBram Moolenaar 	    return tv->vval.v_list != NULL && tv->vval.v_list->lv_len > 0;
20998a7d6542SBram Moolenaar 	case VAR_DICT:
21008a7d6542SBram Moolenaar 	    return tv->vval.v_dict != NULL
21018a7d6542SBram Moolenaar 				    && tv->vval.v_dict->dv_hashtab.ht_used > 0;
21028a7d6542SBram Moolenaar 	case VAR_BOOL:
21038a7d6542SBram Moolenaar 	case VAR_SPECIAL:
21048a7d6542SBram Moolenaar 	    return tv->vval.v_number == VVAL_TRUE ? TRUE : FALSE;
21058a7d6542SBram Moolenaar 	case VAR_JOB:
21068a7d6542SBram Moolenaar #ifdef FEAT_JOB_CHANNEL
21078a7d6542SBram Moolenaar 	    return tv->vval.v_job != NULL;
21088a7d6542SBram Moolenaar #else
21098a7d6542SBram Moolenaar 	    break;
21108a7d6542SBram Moolenaar #endif
21118a7d6542SBram Moolenaar 	case VAR_CHANNEL:
21128a7d6542SBram Moolenaar #ifdef FEAT_JOB_CHANNEL
21138a7d6542SBram Moolenaar 	    return tv->vval.v_channel != NULL;
21148a7d6542SBram Moolenaar #else
21158a7d6542SBram Moolenaar 	    break;
21168a7d6542SBram Moolenaar #endif
21178a7d6542SBram Moolenaar 	case VAR_BLOB:
21188a7d6542SBram Moolenaar 	    return tv->vval.v_blob != NULL && tv->vval.v_blob->bv_ga.ga_len > 0;
21198a7d6542SBram Moolenaar 	case VAR_UNKNOWN:
21208a7d6542SBram Moolenaar 	case VAR_VOID:
21218a7d6542SBram Moolenaar 	    break;
21228a7d6542SBram Moolenaar     }
21238a7d6542SBram Moolenaar     return FALSE;
21248a7d6542SBram Moolenaar }
21258a7d6542SBram Moolenaar 
21268a7d6542SBram Moolenaar /*
21278a7d6542SBram Moolenaar  * If "tv" is a string give an error and return FAIL.
21288a7d6542SBram Moolenaar  */
21298a7d6542SBram Moolenaar     int
21308a7d6542SBram Moolenaar check_not_string(typval_T *tv)
21318a7d6542SBram Moolenaar {
21328a7d6542SBram Moolenaar     if (tv->v_type == VAR_STRING)
21338a7d6542SBram Moolenaar     {
21348a7d6542SBram Moolenaar 	emsg(_("E1030: Using a String as a Number"));
21358a7d6542SBram Moolenaar 	clear_tv(tv);
21368a7d6542SBram Moolenaar 	return FAIL;
21378a7d6542SBram Moolenaar     }
21388a7d6542SBram Moolenaar     return OK;
21398a7d6542SBram Moolenaar }
21408a7d6542SBram Moolenaar 
21418a7d6542SBram Moolenaar 
21428a7d6542SBram Moolenaar #endif // FEAT_EVAL
2143