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