blob: d4ffb9331307dbf275d10e854c14ab9db4590806 [file] [log] [blame]
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001/* vi:set ts=8 sts=4 sw=4 noet:
2 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 *
5 * Do ":help uganda" in Vim to read copying and usage conditions.
6 * Do ":help credits" in Vim to see a list of people who contributed.
7 * See README.txt for an overview of the Vim source code.
8 */
9
10/*
11 * vim9cmds.c: Dealing with commands of a compiled function
12 */
13
14#define USING_FLOAT_STUFF
15#include "vim.h"
16
17#if defined(FEAT_EVAL) || defined(PROTO)
18
19// When not generating protos this is included in proto.h
20#ifdef PROTO
21# include "vim9.h"
22#endif
23
24/*
25 * Get the index of the current instruction.
26 * This compensates for a preceding ISN_CMDMOD and ISN_PROF_START.
27 */
28 static int
29current_instr_idx(cctx_T *cctx)
30{
31 garray_T *instr = &cctx->ctx_instr;
32 int idx = instr->ga_len;
33
34 while (idx > 0)
35 {
36 if (cctx->ctx_has_cmdmod && ((isn_T *)instr->ga_data)[idx - 1]
37 .isn_type == ISN_CMDMOD)
38 {
39 --idx;
40 continue;
41 }
42#ifdef FEAT_PROFILE
43 if (((isn_T *)instr->ga_data)[idx - 1].isn_type == ISN_PROF_START)
44 {
45 --idx;
46 continue;
47 }
48#endif
49 if (((isn_T *)instr->ga_data)[idx - 1].isn_type == ISN_DEBUG)
50 {
51 --idx;
52 continue;
53 }
54 break;
55 }
56 return idx;
57}
58/*
59 * Remove local variables above "new_top".
Bram Moolenaara275f2c2022-10-11 20:04:09 +010060 * Do this by clearing the name. If "keep" is TRUE do not reset the length, a
61 * closure may still need location of the variable.
Bram Moolenaardc7c3662021-12-20 15:04:29 +000062 */
63 static void
Bram Moolenaara275f2c2022-10-11 20:04:09 +010064unwind_locals(cctx_T *cctx, int new_top, int keep)
Bram Moolenaardc7c3662021-12-20 15:04:29 +000065{
66 if (cctx->ctx_locals.ga_len > new_top)
Bram Moolenaara275f2c2022-10-11 20:04:09 +010067 for (int idx = new_top; idx < cctx->ctx_locals.ga_len; ++idx)
Bram Moolenaardc7c3662021-12-20 15:04:29 +000068 {
Bram Moolenaara275f2c2022-10-11 20:04:09 +010069 lvar_T *lvar = ((lvar_T *)cctx->ctx_locals.ga_data) + idx;
70 VIM_CLEAR(lvar->lv_name);
Bram Moolenaardc7c3662021-12-20 15:04:29 +000071 }
Bram Moolenaara275f2c2022-10-11 20:04:09 +010072 if (!keep)
73 cctx->ctx_locals.ga_len = new_top;
Bram Moolenaardc7c3662021-12-20 15:04:29 +000074}
75
76/*
77 * Free all local variables.
78 */
79 void
80free_locals(cctx_T *cctx)
81{
Bram Moolenaara275f2c2022-10-11 20:04:09 +010082 unwind_locals(cctx, 0, FALSE);
Bram Moolenaardc7c3662021-12-20 15:04:29 +000083 ga_clear(&cctx->ctx_locals);
84}
85
86
87/*
88 * Check if "name" can be "unlet".
89 */
90 int
91check_vim9_unlet(char_u *name)
92{
Bram Moolenaardbdd16b2022-08-14 21:46:07 +010093 if (*name == NUL)
94 {
95 semsg(_(e_argument_required_for_str), "unlet");
96 return FAIL;
97 }
98
Bram Moolenaardc7c3662021-12-20 15:04:29 +000099 if (name[1] != ':' || vim_strchr((char_u *)"gwtb", *name) == NULL)
100 {
101 // "unlet s:var" is allowed in legacy script.
Hirohito Higashif5bfc482025-05-01 08:56:39 +0200102 if (*name == 's' && !in_vim9script())
Bram Moolenaardc7c3662021-12-20 15:04:29 +0000103 return OK;
104 semsg(_(e_cannot_unlet_str), name);
105 return FAIL;
106 }
107 return OK;
108}
109
110/*
111 * Callback passed to ex_unletlock().
112 */
113 static int
114compile_unlet(
115 lval_T *lvp,
116 char_u *name_end,
117 exarg_T *eap,
118 int deep UNUSED,
119 void *coookie)
120{
121 cctx_T *cctx = coookie;
122 char_u *p = lvp->ll_name;
123 int cc = *name_end;
124 int ret = OK;
125
126 if (cctx->ctx_skip == SKIP_YES)
127 return OK;
128
129 *name_end = NUL;
130 if (*p == '$')
131 {
132 // :unlet $ENV_VAR
133 ret = generate_UNLET(cctx, ISN_UNLETENV, p + 1, eap->forceit);
134 }
135 else if (vim_strchr(p, '.') != NULL || vim_strchr(p, '[') != NULL)
136 {
137 lhs_T lhs;
138
139 // This is similar to assigning: lookup the list/dict, compile the
140 // idx/key. Then instead of storing the value unlet the item.
141 // unlet {list}[idx]
142 // unlet {dict}[key] dict.key
143 //
144 // Figure out the LHS type and other properties.
145 //
Bram Moolenaar97f8c102022-04-02 19:43:57 +0100146 ret = compile_lhs(p, &lhs, CMD_unlet, FALSE, FALSE, 0, cctx);
Bram Moolenaardc7c3662021-12-20 15:04:29 +0000147
Bram Moolenaar2ef01d92022-01-06 21:38:11 +0000148 // Use the info in "lhs" to unlet the item at the index in the
149 // list or dict.
150 if (ret == OK)
Bram Moolenaardc7c3662021-12-20 15:04:29 +0000151 {
Bram Moolenaar2ef01d92022-01-06 21:38:11 +0000152 if (!lhs.lhs_has_index)
153 {
154 semsg(_(e_cannot_unlet_imported_item_str), p);
155 ret = FAIL;
156 }
157 else
158 ret = compile_assign_unlet(p, &lhs, FALSE, &t_void, cctx);
Bram Moolenaardc7c3662021-12-20 15:04:29 +0000159 }
160
161 vim_free(lhs.lhs_name);
162 }
163 else if (check_vim9_unlet(p) == FAIL)
164 {
165 ret = FAIL;
166 }
167 else
168 {
169 // Normal name. Only supports g:, w:, t: and b: namespaces.
170 ret = generate_UNLET(cctx, ISN_UNLET, p, eap->forceit);
171 }
172
173 *name_end = cc;
174 return ret;
175}
176
177/*
178 * Callback passed to ex_unletlock().
179 */
180 static int
181compile_lock_unlock(
182 lval_T *lvp,
183 char_u *name_end,
184 exarg_T *eap,
Bram Moolenaar70c43d82022-01-26 21:01:15 +0000185 int deep,
Bram Moolenaardc7c3662021-12-20 15:04:29 +0000186 void *coookie)
187{
188 cctx_T *cctx = coookie;
189 int cc = *name_end;
190 char_u *p = lvp->ll_name;
191 int ret = OK;
Bram Moolenaardc7c3662021-12-20 15:04:29 +0000192 char_u *buf;
193 isntype_T isn = ISN_EXEC;
Bram Moolenaard1d8f6b2022-08-14 21:28:32 +0100194 char *cmd = eap->cmdidx == CMD_lockvar ? "lockvar" : "unlockvar";
Ernie Raelee865f32023-09-29 19:53:55 +0200195 int is_arg = FALSE;
196
197#ifdef LOG_LOCKVAR
198 ch_log(NULL, "LKVAR: compile_lock_unlock(): cookie %p, name %s",
199 coookie, p);
200#endif
Bram Moolenaardc7c3662021-12-20 15:04:29 +0000201
202 if (cctx->ctx_skip == SKIP_YES)
203 return OK;
204
Bram Moolenaard1d8f6b2022-08-14 21:28:32 +0100205 if (*p == NUL)
206 {
207 semsg(_(e_argument_required_for_str), cmd);
208 return FAIL;
209 }
210
Bram Moolenaardc7c3662021-12-20 15:04:29 +0000211 // Cannot use :lockvar and :unlockvar on local variables.
212 if (p[1] != ':')
213 {
214 char_u *end = find_name_end(p, NULL, NULL, FNE_CHECK_START);
Ernie Rael64885642023-10-04 20:16:22 +0200215
216 // The most important point is that something like
217 // name[idx].member... needs to be resolved at runtime, get_lval(),
218 // starting from the root "name".
219
220 // These checks are reminiscent of the variable_exists function.
221 // But most of the matches require special handling.
222
223 // If bare name is is locally accessible, except for local var,
Ernie Raelee865f32023-09-29 19:53:55 +0200224 // then put it on the stack to use with ISN_LOCKUNLOCK.
225 // This could be v.memb, v[idx_key]; bare class variable,
Ernie Rael64885642023-10-04 20:16:22 +0200226 // function arg. The item on the stack, will be passed
227 // to ex_lockvar() indirectly and be used as the root for get_lval.
228 // A bare script variable name needs no special handling.
Bram Moolenaardc7c3662021-12-20 15:04:29 +0000229
Ernie Raelee865f32023-09-29 19:53:55 +0200230 char_u *name = NULL;
231 int len = end - p;
232
233 if (lookup_local(p, len, NULL, cctx) == OK)
Bram Moolenaardc7c3662021-12-20 15:04:29 +0000234 {
Ernie Raelee865f32023-09-29 19:53:55 +0200235 // Handle "this", "this.val", "anyvar[idx]"
236 if (*end != '.' && *end != '['
237 && (len != 4 || STRNCMP("this", p, len) != 0))
Bram Moolenaardc7c3662021-12-20 15:04:29 +0000238 {
239 emsg(_(e_cannot_lock_unlock_local_variable));
240 return FAIL;
241 }
Ernie Raelee865f32023-09-29 19:53:55 +0200242 // Push the local on the stack, could be "this".
243 name = p;
244#ifdef LOG_LOCKVAR
Ernie Rael64885642023-10-04 20:16:22 +0200245 ch_log(NULL, "LKVAR: ... lookup_local: name %s", name);
Ernie Raelee865f32023-09-29 19:53:55 +0200246#endif
247 }
248 if (name == NULL)
249 {
250 class_T *cl;
251 if (cctx_class_member_idx(cctx, p, len, &cl) >= 0)
252 {
253 if (*end != '.' && *end != '[')
254 {
255 // Push the class of the bare class variable name
256 name = cl->class_name;
Yegappan Lakshmananb8523052023-10-08 19:07:39 +0200257 len = (int)STRLEN(name);
Ernie Raelee865f32023-09-29 19:53:55 +0200258#ifdef LOG_LOCKVAR
Ernie Rael64885642023-10-04 20:16:22 +0200259 ch_log(NULL, "LKVAR: ... cctx_class_member: name %s",
Ernie Raelee865f32023-09-29 19:53:55 +0200260 name);
261#endif
262 }
263 }
264 }
265 if (name == NULL)
266 {
Ernie Raelee865f32023-09-29 19:53:55 +0200267 // Can lockvar any function arg.
Ernie Rael64885642023-10-04 20:16:22 +0200268 if (arg_exists(p, len, NULL, NULL, NULL, cctx) == OK)
Ernie Raelee865f32023-09-29 19:53:55 +0200269 {
270 name = p;
271 is_arg = TRUE;
272#ifdef LOG_LOCKVAR
Ernie Rael64885642023-10-04 20:16:22 +0200273 ch_log(NULL, "LKVAR: ... arg_exists: name %s", name);
274#endif
275 }
276 }
277 if (name == NULL)
278 {
279 // No special handling for a bare script variable; but
280 // if followed by '[' or '.', it's a root for get_lval().
281 if (script_var_exists(p, len, cctx, NULL) == OK
282 && (*end == '.' || *end == '['))
283 {
284 name = p;
285#ifdef LOG_LOCKVAR
286 ch_log(NULL, "LKVAR: ... script_var_exists: name %s", name);
Ernie Raelee865f32023-09-29 19:53:55 +0200287#endif
288 }
289 }
290 if (name != NULL)
291 {
292#ifdef LOG_LOCKVAR
Ernie Rael64885642023-10-04 20:16:22 +0200293 ch_log(NULL, "LKVAR: ... INS_LOCKUNLOCK %s", name);
Ernie Raelee865f32023-09-29 19:53:55 +0200294#endif
295 if (compile_load(&name, name + len, cctx, FALSE, FALSE) == FAIL)
Bram Moolenaardc7c3662021-12-20 15:04:29 +0000296 return FAIL;
297 isn = ISN_LOCKUNLOCK;
298 }
299 }
300
301 // Checking is done at runtime.
302 *name_end = NUL;
Ernie Raelee865f32023-09-29 19:53:55 +0200303 size_t len = name_end - p + 20;
Bram Moolenaardc7c3662021-12-20 15:04:29 +0000304 buf = alloc(len);
305 if (buf == NULL)
306 ret = FAIL;
307 else
308 {
Bram Moolenaare939f5e2022-01-26 21:32:59 +0000309 if (deep < 0)
310 vim_snprintf((char *)buf, len, "%s! %s", cmd, p);
311 else
312 vim_snprintf((char *)buf, len, "%s %d %s", cmd, deep, p);
Ernie Raelee865f32023-09-29 19:53:55 +0200313#ifdef LOG_LOCKVAR
Ernie Rael64885642023-10-04 20:16:22 +0200314 ch_log(NULL, "LKVAR: ... buf %s", buf);
Ernie Raelee865f32023-09-29 19:53:55 +0200315#endif
316 if (isn == ISN_LOCKUNLOCK)
317 ret = generate_LOCKUNLOCK(cctx, buf, is_arg);
318 else
319 ret = generate_EXEC_copy(cctx, isn, buf);
Bram Moolenaardc7c3662021-12-20 15:04:29 +0000320
321 vim_free(buf);
322 *name_end = cc;
323 }
324 return ret;
325}
326
327/*
328 * compile "unlet var", "lock var" and "unlock var"
329 * "arg" points to "var".
330 */
331 char_u *
332compile_unletlock(char_u *arg, exarg_T *eap, cctx_T *cctx)
333{
Bram Moolenaar70c43d82022-01-26 21:01:15 +0000334 int deep = 0;
335 char_u *p = arg;
336
337 if (eap->cmdidx != CMD_unlet)
338 {
339 if (eap->forceit)
340 deep = -1;
341 else if (vim_isdigit(*p))
342 {
343 deep = getdigits(&p);
344 p = skipwhite(p);
345 }
346 else
347 deep = 2;
348 }
349
350 ex_unletlock(eap, p, deep, GLV_NO_AUTOLOAD | GLV_COMPILING,
Bram Moolenaardc7c3662021-12-20 15:04:29 +0000351 eap->cmdidx == CMD_unlet ? compile_unlet : compile_lock_unlock,
352 cctx);
353 return eap->nextcmd == NULL ? (char_u *)"" : eap->nextcmd;
354}
355
356/*
Bram Moolenaarb46c0832022-09-15 17:19:37 +0100357 * Generate a jump to the ":endif"/":endfor"/":endwhile"/":finally"/":endtry".
358 * "funcref_idx" is used for JUMP_WHILE_FALSE
Bram Moolenaardc7c3662021-12-20 15:04:29 +0000359 */
360 static int
Bram Moolenaarb46c0832022-09-15 17:19:37 +0100361compile_jump_to_end(
362 endlabel_T **el,
363 jumpwhen_T when,
364 int funcref_idx,
365 cctx_T *cctx)
Bram Moolenaardc7c3662021-12-20 15:04:29 +0000366{
367 garray_T *instr = &cctx->ctx_instr;
368 endlabel_T *endlabel = ALLOC_CLEAR_ONE(endlabel_T);
369
370 if (endlabel == NULL)
371 return FAIL;
372 endlabel->el_next = *el;
373 *el = endlabel;
374 endlabel->el_end_label = instr->ga_len;
375
Bram Moolenaarb46c0832022-09-15 17:19:37 +0100376 if (when == JUMP_WHILE_FALSE)
377 generate_WHILE(cctx, funcref_idx);
378 else
379 generate_JUMP(cctx, when, 0);
Bram Moolenaardc7c3662021-12-20 15:04:29 +0000380 return OK;
381}
382
383 static void
384compile_fill_jump_to_end(endlabel_T **el, int jump_where, cctx_T *cctx)
385{
386 garray_T *instr = &cctx->ctx_instr;
387
388 while (*el != NULL)
389 {
390 endlabel_T *cur = (*el);
391 isn_T *isn;
392
393 isn = ((isn_T *)instr->ga_data) + cur->el_end_label;
394 isn->isn_arg.jump.jump_where = jump_where;
395 *el = cur->el_next;
396 vim_free(cur);
397 }
398}
399
400 static void
401compile_free_jump_to_end(endlabel_T **el)
402{
403 while (*el != NULL)
404 {
405 endlabel_T *cur = (*el);
406
407 *el = cur->el_next;
408 vim_free(cur);
409 }
410}
411
412/*
413 * Create a new scope and set up the generic items.
414 */
415 static scope_T *
416new_scope(cctx_T *cctx, scopetype_T type)
417{
418 scope_T *scope = ALLOC_CLEAR_ONE(scope_T);
419
420 if (scope == NULL)
421 return NULL;
422 scope->se_outer = cctx->ctx_scope;
423 cctx->ctx_scope = scope;
424 scope->se_type = type;
425 scope->se_local_count = cctx->ctx_locals.ga_len;
Bram Moolenaarcc341812022-09-19 15:54:34 +0100426 if (scope->se_outer != NULL)
427 scope->se_loop_depth = scope->se_outer->se_loop_depth;
Bram Moolenaardc7c3662021-12-20 15:04:29 +0000428 return scope;
429}
430
431/*
432 * Free the current scope and go back to the outer scope.
433 */
434 void
435drop_scope(cctx_T *cctx)
436{
437 scope_T *scope = cctx->ctx_scope;
438
439 if (scope == NULL)
440 {
441 iemsg("calling drop_scope() without a scope");
442 return;
443 }
444 cctx->ctx_scope = scope->se_outer;
445 switch (scope->se_type)
446 {
447 case IF_SCOPE:
448 compile_free_jump_to_end(&scope->se_u.se_if.is_end_label); break;
449 case FOR_SCOPE:
450 compile_free_jump_to_end(&scope->se_u.se_for.fs_end_label); break;
451 case WHILE_SCOPE:
452 compile_free_jump_to_end(&scope->se_u.se_while.ws_end_label); break;
453 case TRY_SCOPE:
454 compile_free_jump_to_end(&scope->se_u.se_try.ts_end_label); break;
455 case NO_SCOPE:
456 case BLOCK_SCOPE:
457 break;
458 }
459 vim_free(scope);
460}
461
462 static int
463misplaced_cmdmod(cctx_T *cctx)
464{
465 garray_T *instr = &cctx->ctx_instr;
466
467 if (cctx->ctx_has_cmdmod
468 && ((isn_T *)instr->ga_data)[instr->ga_len - 1].isn_type
469 == ISN_CMDMOD)
470 {
471 emsg(_(e_misplaced_command_modifier));
472 return TRUE;
473 }
474 return FALSE;
475}
476
477/*
478 * compile "if expr"
479 *
480 * "if expr" Produces instructions:
481 * EVAL expr Push result of "expr"
482 * JUMP_IF_FALSE end
483 * ... body ...
484 * end:
485 *
486 * "if expr | else" Produces instructions:
487 * EVAL expr Push result of "expr"
488 * JUMP_IF_FALSE else
489 * ... body ...
490 * JUMP_ALWAYS end
491 * else:
492 * ... body ...
493 * end:
494 *
495 * "if expr1 | elseif expr2 | else" Produces instructions:
496 * EVAL expr Push result of "expr"
497 * JUMP_IF_FALSE elseif
498 * ... body ...
499 * JUMP_ALWAYS end
500 * elseif:
501 * EVAL expr Push result of "expr"
502 * JUMP_IF_FALSE else
503 * ... body ...
504 * JUMP_ALWAYS end
505 * else:
506 * ... body ...
507 * end:
508 */
509 char_u *
510compile_if(char_u *arg, cctx_T *cctx)
511{
512 char_u *p = arg;
513 garray_T *instr = &cctx->ctx_instr;
514 int instr_count = instr->ga_len;
515 scope_T *scope;
516 skip_T skip_save = cctx->ctx_skip;
517 ppconst_T ppconst;
518
519 CLEAR_FIELD(ppconst);
520 if (compile_expr1(&p, cctx, &ppconst) == FAIL)
521 {
522 clear_ppconst(&ppconst);
523 return NULL;
524 }
525 if (!ends_excmd2(arg, skipwhite(p)))
526 {
Bram Moolenaar74409f62022-01-01 15:58:22 +0000527 semsg(_(e_trailing_characters_str), p);
Bram Moolenaardc7c3662021-12-20 15:04:29 +0000528 return NULL;
529 }
530 if (cctx->ctx_skip == SKIP_YES)
531 clear_ppconst(&ppconst);
532 else if (instr->ga_len == instr_count && ppconst.pp_used == 1)
533 {
534 int error = FALSE;
535 int v;
536
537 // The expression results in a constant.
538 v = tv_get_bool_chk(&ppconst.pp_tv[0], &error);
539 clear_ppconst(&ppconst);
540 if (error)
541 return NULL;
542 cctx->ctx_skip = v ? SKIP_NOT : SKIP_YES;
543 }
544 else
545 {
546 // Not a constant, generate instructions for the expression.
547 cctx->ctx_skip = SKIP_UNKNOWN;
548 if (generate_ppconst(cctx, &ppconst) == FAIL)
549 return NULL;
550 if (bool_on_stack(cctx) == FAIL)
551 return NULL;
552 }
553
554 // CMDMOD_REV must come before the jump
555 generate_undo_cmdmods(cctx);
556
557 scope = new_scope(cctx, IF_SCOPE);
558 if (scope == NULL)
559 return NULL;
560 scope->se_skip_save = skip_save;
561 // "is_had_return" will be reset if any block does not end in :return
562 scope->se_u.se_if.is_had_return = TRUE;
563
564 if (cctx->ctx_skip == SKIP_UNKNOWN)
565 {
566 // "where" is set when ":elseif", "else" or ":endif" is found
567 scope->se_u.se_if.is_if_label = instr->ga_len;
568 generate_JUMP(cctx, JUMP_IF_FALSE, 0);
569 }
570 else
571 scope->se_u.se_if.is_if_label = -1;
572
573#ifdef FEAT_PROFILE
574 if (cctx->ctx_compile_type == CT_PROFILE && cctx->ctx_skip == SKIP_YES
575 && skip_save != SKIP_YES)
576 {
577 // generated a profile start, need to generate a profile end, since it
578 // won't be done after returning
579 cctx->ctx_skip = SKIP_NOT;
580 generate_instr(cctx, ISN_PROF_END);
581 cctx->ctx_skip = SKIP_YES;
582 }
583#endif
584
585 return p;
586}
587
588 char_u *
589compile_elseif(char_u *arg, cctx_T *cctx)
590{
591 char_u *p = arg;
592 garray_T *instr = &cctx->ctx_instr;
593 int instr_count;
594 isn_T *isn;
595 scope_T *scope = cctx->ctx_scope;
596 ppconst_T ppconst;
597 skip_T save_skip = cctx->ctx_skip;
598
599 if (scope == NULL || scope->se_type != IF_SCOPE)
600 {
601 emsg(_(e_elseif_without_if));
602 return NULL;
603 }
Bram Moolenaara275f2c2022-10-11 20:04:09 +0100604 unwind_locals(cctx, scope->se_local_count, TRUE);
Yegappan Lakshmananab9a8942024-12-30 09:56:34 +0100605 if (!cctx->ctx_had_return && !cctx->ctx_had_throw)
606 // the previous if block didn't end in a "return" or a "throw"
607 // statement.
Bram Moolenaardc7c3662021-12-20 15:04:29 +0000608 scope->se_u.se_if.is_had_return = FALSE;
609
610 if (cctx->ctx_skip == SKIP_NOT)
611 {
612 // previous block was executed, this one and following will not
613 cctx->ctx_skip = SKIP_YES;
614 scope->se_u.se_if.is_seen_skip_not = TRUE;
615 }
616 if (scope->se_u.se_if.is_seen_skip_not)
617 {
618 // A previous block was executed, skip over expression and bail out.
619 // Do not count the "elseif" for profiling and cmdmod
620 instr->ga_len = current_instr_idx(cctx);
621
622 skip_expr_cctx(&p, cctx);
623 return p;
624 }
625
626 if (cctx->ctx_skip == SKIP_UNKNOWN)
627 {
628 int moved_cmdmod = FALSE;
629 int saved_debug = FALSE;
630 isn_T debug_isn;
631
632 // Move any CMDMOD instruction to after the jump
633 if (((isn_T *)instr->ga_data)[instr->ga_len - 1].isn_type == ISN_CMDMOD)
634 {
635 if (GA_GROW_FAILS(instr, 1))
636 return NULL;
637 ((isn_T *)instr->ga_data)[instr->ga_len] =
638 ((isn_T *)instr->ga_data)[instr->ga_len - 1];
639 --instr->ga_len;
640 moved_cmdmod = TRUE;
641 }
642
643 // Remove the already generated ISN_DEBUG, it is written below the
644 // ISN_FOR instruction.
645 if (cctx->ctx_compile_type == CT_DEBUG && instr->ga_len > 0
646 && ((isn_T *)instr->ga_data)[instr->ga_len - 1]
647 .isn_type == ISN_DEBUG)
648 {
649 --instr->ga_len;
650 debug_isn = ((isn_T *)instr->ga_data)[instr->ga_len];
651 saved_debug = TRUE;
652 }
653
654 if (compile_jump_to_end(&scope->se_u.se_if.is_end_label,
Bram Moolenaarb46c0832022-09-15 17:19:37 +0100655 JUMP_ALWAYS, 0, cctx) == FAIL)
Bram Moolenaardc7c3662021-12-20 15:04:29 +0000656 return NULL;
657 // previous "if" or "elseif" jumps here
658 isn = ((isn_T *)instr->ga_data) + scope->se_u.se_if.is_if_label;
659 isn->isn_arg.jump.jump_where = instr->ga_len;
660
661 if (moved_cmdmod)
662 ++instr->ga_len;
663
664 if (saved_debug)
665 {
666 // move the debug instruction here
667 if (GA_GROW_FAILS(instr, 1))
668 return NULL;
669 ((isn_T *)instr->ga_data)[instr->ga_len] = debug_isn;
670 ++instr->ga_len;
671 }
672 }
673
674 // compile "expr"; if we know it evaluates to FALSE skip the block
675 CLEAR_FIELD(ppconst);
676 if (cctx->ctx_skip == SKIP_YES)
677 {
678 cctx->ctx_skip = SKIP_UNKNOWN;
679#ifdef FEAT_PROFILE
680 if (cctx->ctx_compile_type == CT_PROFILE)
681 // the previous block was skipped, need to profile this line
682 generate_instr(cctx, ISN_PROF_START);
683#endif
684 if (cctx->ctx_compile_type == CT_DEBUG)
685 // the previous block was skipped, may want to debug this line
686 generate_instr_debug(cctx);
687 }
688
689 instr_count = instr->ga_len;
690 if (compile_expr1(&p, cctx, &ppconst) == FAIL)
691 {
692 clear_ppconst(&ppconst);
693 return NULL;
694 }
695 cctx->ctx_skip = save_skip;
696 if (!ends_excmd2(arg, skipwhite(p)))
697 {
698 clear_ppconst(&ppconst);
Bram Moolenaar74409f62022-01-01 15:58:22 +0000699 semsg(_(e_trailing_characters_str), p);
Bram Moolenaardc7c3662021-12-20 15:04:29 +0000700 return NULL;
701 }
702 if (scope->se_skip_save == SKIP_YES)
703 clear_ppconst(&ppconst);
704 else if (instr->ga_len == instr_count && ppconst.pp_used == 1)
705 {
706 int error = FALSE;
707 int v;
708
709 // The expression result is a constant.
710 v = tv_get_bool_chk(&ppconst.pp_tv[0], &error);
711 if (error)
712 {
713 clear_ppconst(&ppconst);
714 return NULL;
715 }
716 cctx->ctx_skip = v ? SKIP_NOT : SKIP_YES;
717 clear_ppconst(&ppconst);
718 scope->se_u.se_if.is_if_label = -1;
719 }
720 else
721 {
722 // Not a constant, generate instructions for the expression.
723 cctx->ctx_skip = SKIP_UNKNOWN;
724 if (generate_ppconst(cctx, &ppconst) == FAIL)
725 return NULL;
726 if (bool_on_stack(cctx) == FAIL)
727 return NULL;
728
729 // CMDMOD_REV must come before the jump
730 generate_undo_cmdmods(cctx);
731
732 // "where" is set when ":elseif", "else" or ":endif" is found
733 scope->se_u.se_if.is_if_label = instr->ga_len;
734 generate_JUMP(cctx, JUMP_IF_FALSE, 0);
735 }
736
737 return p;
738}
739
740 char_u *
741compile_else(char_u *arg, cctx_T *cctx)
742{
743 char_u *p = arg;
744 garray_T *instr = &cctx->ctx_instr;
745 isn_T *isn;
746 scope_T *scope = cctx->ctx_scope;
747
748 if (scope == NULL || scope->se_type != IF_SCOPE)
749 {
750 emsg(_(e_else_without_if));
751 return NULL;
752 }
Bram Moolenaara275f2c2022-10-11 20:04:09 +0100753 unwind_locals(cctx, scope->se_local_count, TRUE);
Yegappan Lakshmananab9a8942024-12-30 09:56:34 +0100754 if (!cctx->ctx_had_return && !cctx->ctx_had_throw)
755 // the previous if block didn't end in a "return" or a "throw"
756 // statement.
Bram Moolenaardc7c3662021-12-20 15:04:29 +0000757 scope->se_u.se_if.is_had_return = FALSE;
758 scope->se_u.se_if.is_seen_else = TRUE;
759
760#ifdef FEAT_PROFILE
761 if (cctx->ctx_compile_type == CT_PROFILE)
762 {
763 if (cctx->ctx_skip == SKIP_NOT
764 && ((isn_T *)instr->ga_data)[instr->ga_len - 1]
765 .isn_type == ISN_PROF_START)
766 // the previous block was executed, do not count "else" for
767 // profiling
768 --instr->ga_len;
769 if (cctx->ctx_skip == SKIP_YES && !scope->se_u.se_if.is_seen_skip_not)
770 {
771 // the previous block was not executed, this one will, do count the
772 // "else" for profiling
773 cctx->ctx_skip = SKIP_NOT;
774 generate_instr(cctx, ISN_PROF_END);
775 generate_instr(cctx, ISN_PROF_START);
776 cctx->ctx_skip = SKIP_YES;
777 }
778 }
779#endif
780
781 if (!scope->se_u.se_if.is_seen_skip_not && scope->se_skip_save != SKIP_YES)
782 {
783 // jump from previous block to the end, unless the else block is empty
784 if (cctx->ctx_skip == SKIP_UNKNOWN)
785 {
786 if (!cctx->ctx_had_return
787 && compile_jump_to_end(&scope->se_u.se_if.is_end_label,
Bram Moolenaarb46c0832022-09-15 17:19:37 +0100788 JUMP_ALWAYS, 0, cctx) == FAIL)
Bram Moolenaardc7c3662021-12-20 15:04:29 +0000789 return NULL;
790 }
791
792 if (cctx->ctx_skip == SKIP_UNKNOWN)
793 {
794 if (scope->se_u.se_if.is_if_label >= 0)
795 {
796 // previous "if" or "elseif" jumps here
797 isn = ((isn_T *)instr->ga_data) + scope->se_u.se_if.is_if_label;
798 isn->isn_arg.jump.jump_where = instr->ga_len;
799 scope->se_u.se_if.is_if_label = -1;
800 }
801 }
802
803 if (cctx->ctx_skip != SKIP_UNKNOWN)
804 cctx->ctx_skip = cctx->ctx_skip == SKIP_YES ? SKIP_NOT : SKIP_YES;
805 }
806
807 return p;
808}
809
810 char_u *
811compile_endif(char_u *arg, cctx_T *cctx)
812{
813 scope_T *scope = cctx->ctx_scope;
814 ifscope_T *ifscope;
815 garray_T *instr = &cctx->ctx_instr;
816 isn_T *isn;
817
818 if (misplaced_cmdmod(cctx))
819 return NULL;
820
821 if (scope == NULL || scope->se_type != IF_SCOPE)
822 {
823 emsg(_(e_endif_without_if));
824 return NULL;
825 }
826 ifscope = &scope->se_u.se_if;
Bram Moolenaara275f2c2022-10-11 20:04:09 +0100827 unwind_locals(cctx, scope->se_local_count, TRUE);
Yegappan Lakshmananab9a8942024-12-30 09:56:34 +0100828 if (!cctx->ctx_had_return && !cctx->ctx_had_throw)
829 // the previous if block didn't end in a "return" or a "throw"
830 // statement.
Bram Moolenaardc7c3662021-12-20 15:04:29 +0000831 ifscope->is_had_return = FALSE;
832
833 if (scope->se_u.se_if.is_if_label >= 0)
834 {
835 // previous "if" or "elseif" jumps here
836 isn = ((isn_T *)instr->ga_data) + scope->se_u.se_if.is_if_label;
837 isn->isn_arg.jump.jump_where = instr->ga_len;
838 }
839 // Fill in the "end" label in jumps at the end of the blocks.
840 compile_fill_jump_to_end(&ifscope->is_end_label, instr->ga_len, cctx);
841
842#ifdef FEAT_PROFILE
843 // even when skipping we count the endif as executed, unless the block it's
844 // in is skipped
845 if (cctx->ctx_compile_type == CT_PROFILE && cctx->ctx_skip == SKIP_YES
846 && scope->se_skip_save != SKIP_YES)
847 {
848 cctx->ctx_skip = SKIP_NOT;
849 generate_instr(cctx, ISN_PROF_START);
850 }
851#endif
852 cctx->ctx_skip = scope->se_skip_save;
853
854 // If all the blocks end in :return and there is an :else then the
855 // had_return flag is set.
856 cctx->ctx_had_return = ifscope->is_had_return && ifscope->is_seen_else;
857
858 drop_scope(cctx);
859 return arg;
860}
861
862/*
Bram Moolenaar8abb5842022-09-17 12:39:58 +0100863 * Save the info needed for ENDLOOP. Used by :for and :while.
864 */
865 static void
866compile_fill_loop_info(loop_info_T *loop_info, int funcref_idx, cctx_T *cctx)
867{
868 loop_info->li_funcref_idx = funcref_idx;
869 loop_info->li_local_count = cctx->ctx_locals.ga_len;
870 loop_info->li_closure_count = cctx->ctx_closure_count;
871}
872
873/*
Yegappan Lakshmanan9cb865e2025-03-23 16:42:16 +0100874 * When compiling a for loop to iterate over a tuple, get the type of the loop
875 * variable to use.
876 */
877 static type_T *
878compile_for_tuple_get_vartype(type_T *vartype, int var_list)
879{
880 // If this is not a variadic tuple, or all the tuple items don't have
881 // the same type, then use t_any
882 if (!(vartype->tt_flags & TTFLAG_VARARGS) || vartype->tt_argcount != 1)
883 return &t_any;
884
885 // variadic tuple
886 type_T *member_type = vartype->tt_args[0]->tt_member;
887 if (member_type->tt_type == VAR_ANY)
888 return &t_any;
889
890 if (!var_list)
891 // for x in tuple<...list<xxx>>
892 return member_type;
893
894 if (member_type->tt_type == VAR_LIST
895 && member_type->tt_member->tt_type != VAR_ANY)
896 // for [x, y] in tuple<...list<list<xxx>>>
897 return member_type->tt_member;
898 else if (member_type->tt_type == VAR_TUPLE
899 && member_type->tt_flags & TTFLAG_VARARGS
900 && member_type->tt_argcount == 1)
901 // for [x, y] in tuple<...list<tuple<...list<xxx>>>>
902 return member_type->tt_args[0]->tt_member;
903
904 return &t_any;
905}
906
907/*
Bram Moolenaardc7c3662021-12-20 15:04:29 +0000908 * Compile "for var in expr":
909 *
910 * Produces instructions:
Bram Moolenaarb46c0832022-09-15 17:19:37 +0100911 * STORE -1 in loop-idx Set index to -1
912 * EVAL expr Result of "expr" on top of stack
Bram Moolenaardc7c3662021-12-20 15:04:29 +0000913 * top: FOR loop-idx, end Increment index, use list on bottom of stack
914 * - if beyond end, jump to "end"
915 * - otherwise get item from list and push it
Bram Moolenaarb46c0832022-09-15 17:19:37 +0100916 * - store ec_funcrefs in var "loop-idx" + 1
Bram Moolenaardc7c3662021-12-20 15:04:29 +0000917 * STORE var Store item in "var"
918 * ... body ...
Bram Moolenaarb46c0832022-09-15 17:19:37 +0100919 * ENDLOOP funcref-idx off count Only if closure uses local var
920 * JUMP top Jump back to repeat
921 * end: DROP Drop the result of "expr"
Bram Moolenaardc7c3662021-12-20 15:04:29 +0000922 *
923 * Compile "for [var1, var2] in expr" - as above, but instead of "STORE var":
924 * UNPACK 2 Split item in 2
925 * STORE var1 Store item in "var1"
926 * STORE var2 Store item in "var2"
927 */
928 char_u *
929compile_for(char_u *arg_start, cctx_T *cctx)
930{
931 char_u *arg;
932 char_u *arg_end;
933 char_u *name = NULL;
934 char_u *p;
935 char_u *wp;
936 int var_count = 0;
937 int var_list = FALSE;
938 int semicolon = FALSE;
939 size_t varlen;
Bram Moolenaardc7c3662021-12-20 15:04:29 +0000940 garray_T *instr = &cctx->ctx_instr;
941 scope_T *scope;
Bram Moolenaarb46c0832022-09-15 17:19:37 +0100942 forscope_T *forscope;
Bram Moolenaardc7c3662021-12-20 15:04:29 +0000943 lvar_T *loop_lvar; // loop iteration variable
Bram Moolenaarcc341812022-09-19 15:54:34 +0100944 int loop_lvar_idx;
Bram Moolenaarb46c0832022-09-15 17:19:37 +0100945 lvar_T *funcref_lvar;
Bram Moolenaarcc341812022-09-19 15:54:34 +0100946 int funcref_lvar_idx;
Bram Moolenaardc7c3662021-12-20 15:04:29 +0000947 lvar_T *var_lvar; // variable for "var"
948 type_T *vartype;
949 type_T *item_type = &t_any;
950 int idx;
951 int prev_lnum = cctx->ctx_prev_lnum;
952
953 p = skip_var_list(arg_start, TRUE, &var_count, &semicolon, FALSE);
954 if (p == NULL)
955 return NULL;
956 if (var_count == 0)
957 var_count = 1;
958 else
959 var_list = TRUE; // can also be a list of one variable
960
961 // consume "in"
962 wp = p;
963 if (may_get_next_line_error(wp, &p, cctx) == FAIL)
964 return NULL;
965 if (STRNCMP(p, "in", 2) != 0 || !IS_WHITE_OR_NUL(p[2]))
966 {
967 if (*p == ':' && wp != p)
968 semsg(_(e_no_white_space_allowed_before_colon_str), p);
969 else
Bram Moolenaar3a846e62022-01-01 16:21:00 +0000970 emsg(_(e_missing_in_after_for));
Bram Moolenaardc7c3662021-12-20 15:04:29 +0000971 return NULL;
972 }
973 wp = p + 2;
974 if (may_get_next_line_error(wp, &p, cctx) == FAIL)
975 return NULL;
976
Bram Moolenaar2b4ecc22022-01-02 14:08:18 +0000977 // Find the already generated ISN_DEBUG to get the line number for the
978 // instruction written below the ISN_FOR instruction.
Bram Moolenaardc7c3662021-12-20 15:04:29 +0000979 if (cctx->ctx_compile_type == CT_DEBUG && instr->ga_len > 0
980 && ((isn_T *)instr->ga_data)[instr->ga_len - 1]
981 .isn_type == ISN_DEBUG)
982 {
Bram Moolenaar2b4ecc22022-01-02 14:08:18 +0000983 prev_lnum = ((isn_T *)instr->ga_data)[instr->ga_len - 1]
Bram Moolenaardc7c3662021-12-20 15:04:29 +0000984 .isn_arg.debug.dbg_break_lnum;
985 }
986
987 scope = new_scope(cctx, FOR_SCOPE);
988 if (scope == NULL)
989 return NULL;
Bram Moolenaarcc341812022-09-19 15:54:34 +0100990 if (scope->se_loop_depth == MAX_LOOP_DEPTH)
991 {
992 emsg(_(e_loop_nesting_too_deep));
993 return NULL;
994 }
995 ++scope->se_loop_depth;
Bram Moolenaarb46c0832022-09-15 17:19:37 +0100996 forscope = &scope->se_u.se_for;
Bram Moolenaardc7c3662021-12-20 15:04:29 +0000997
998 // Reserve a variable to store the loop iteration counter and initialize it
999 // to -1.
Bram Moolenaar6586a012022-09-30 11:04:50 +01001000 loop_lvar = reserve_local(cctx, (char_u *)"", 0, ASSIGN_VAR, &t_number);
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001001 if (loop_lvar == NULL)
1002 {
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001003 drop_scope(cctx);
Bram Moolenaarb46c0832022-09-15 17:19:37 +01001004 return NULL; // out of memory
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001005 }
Bram Moolenaarcc341812022-09-19 15:54:34 +01001006 // get the index before a following reserve_local() makes the lval invalid
1007 loop_lvar_idx = loop_lvar->lv_idx;
1008 generate_STORENR(cctx, loop_lvar_idx, -1);
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001009
Bram Moolenaarb46c0832022-09-15 17:19:37 +01001010 // Reserve a variable to store ec_funcrefs.ga_len, used in ISN_ENDLOOP.
1011 // The variable index is always the loop var index plus one.
1012 // It is not used when no closures are encountered, we don't know yet.
Bram Moolenaar6586a012022-09-30 11:04:50 +01001013 funcref_lvar = reserve_local(cctx, (char_u *)"", 0, ASSIGN_VAR, &t_number);
Bram Moolenaarb46c0832022-09-15 17:19:37 +01001014 if (funcref_lvar == NULL)
1015 {
1016 drop_scope(cctx);
1017 return NULL; // out of memory
1018 }
Bram Moolenaarcc341812022-09-19 15:54:34 +01001019 // get the index before a following reserve_local() makes the lval invalid
1020 funcref_lvar_idx = funcref_lvar->lv_idx;
Bram Moolenaarb46c0832022-09-15 17:19:37 +01001021
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001022 // compile "expr", it remains on the stack until "endfor"
1023 arg = p;
1024 if (compile_expr0(&arg, cctx) == FAIL)
1025 {
1026 drop_scope(cctx);
1027 return NULL;
1028 }
1029 arg_end = arg;
1030
1031 if (cctx->ctx_skip != SKIP_YES)
1032 {
Dominique Pelleaf4a61a2021-12-27 17:21:41 +00001033 // If we know the type of "var" and it is not a supported type we can
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001034 // give an error now.
Bram Moolenaar078a4612022-01-04 15:17:03 +00001035 vartype = get_type_on_stack(cctx, 0);
Bram Moolenaar59618fe2021-12-21 12:32:17 +00001036 if (vartype->tt_type != VAR_LIST
Yegappan Lakshmanan9cb865e2025-03-23 16:42:16 +01001037 && vartype->tt_type != VAR_TUPLE
Bram Moolenaar59618fe2021-12-21 12:32:17 +00001038 && vartype->tt_type != VAR_STRING
1039 && vartype->tt_type != VAR_BLOB
1040 && vartype->tt_type != VAR_ANY
1041 && vartype->tt_type != VAR_UNKNOWN)
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001042 {
1043 semsg(_(e_for_loop_on_str_not_supported),
1044 vartype_name(vartype->tt_type));
1045 drop_scope(cctx);
1046 return NULL;
1047 }
1048
1049 if (vartype->tt_type == VAR_STRING)
1050 item_type = &t_string;
1051 else if (vartype->tt_type == VAR_BLOB)
1052 item_type = &t_number;
1053 else if (vartype->tt_type == VAR_LIST
1054 && vartype->tt_member->tt_type != VAR_ANY)
1055 {
1056 if (!var_list)
1057 item_type = vartype->tt_member;
1058 else if (vartype->tt_member->tt_type == VAR_LIST
1059 && vartype->tt_member->tt_member->tt_type != VAR_ANY)
1060 item_type = vartype->tt_member->tt_member;
1061 }
Yegappan Lakshmanan9cb865e2025-03-23 16:42:16 +01001062 else if (vartype->tt_type == VAR_TUPLE)
1063 item_type = compile_for_tuple_get_vartype(vartype, var_list);
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001064
1065 // CMDMOD_REV must come before the FOR instruction.
1066 generate_undo_cmdmods(cctx);
1067
1068 // "for_end" is set when ":endfor" is found
Bram Moolenaarb46c0832022-09-15 17:19:37 +01001069 forscope->fs_top_label = current_instr_idx(cctx);
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001070
Bram Moolenaar2b4ecc22022-01-02 14:08:18 +00001071 if (cctx->ctx_compile_type == CT_DEBUG)
1072 {
1073 int save_prev_lnum = cctx->ctx_prev_lnum;
1074 isn_T *isn;
1075
1076 // Add ISN_DEBUG here, before deciding to end the loop. There will
1077 // be another ISN_DEBUG before the next instruction.
1078 // Use the prev_lnum from the ISN_DEBUG instruction removed above.
1079 // Increment the variable count so that the loop variable can be
1080 // inspected.
1081 cctx->ctx_prev_lnum = prev_lnum;
1082 isn = generate_instr_debug(cctx);
1083 ++isn->isn_arg.debug.dbg_var_names_len;
1084 cctx->ctx_prev_lnum = save_prev_lnum;
1085 }
1086
Bram Moolenaarcc341812022-09-19 15:54:34 +01001087 generate_FOR(cctx, loop_lvar_idx);
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001088
1089 arg = arg_start;
1090 if (var_list)
1091 {
1092 generate_UNPACK(cctx, var_count, semicolon);
1093 arg = skipwhite(arg + 1); // skip white after '['
1094
Bram Moolenaar078a4612022-01-04 15:17:03 +00001095 // drop the list item
1096 --cctx->ctx_type_stack.ga_len;
1097
1098 // add type of the items
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001099 for (idx = 0; idx < var_count; ++idx)
1100 {
Bram Moolenaar078a4612022-01-04 15:17:03 +00001101 type_T *type = (semicolon && idx == 0) ? vartype : item_type;
1102
1103 if (push_type_stack(cctx, type) == FAIL)
1104 {
1105 drop_scope(cctx);
1106 return NULL;
1107 }
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001108 }
1109 }
1110
1111 for (idx = 0; idx < var_count; ++idx)
1112 {
1113 assign_dest_T dest = dest_local;
1114 int opt_flags = 0;
1115 int vimvaridx = -1;
1116 type_T *type = &t_any;
1117 type_T *lhs_type = &t_any;
1118 where_T where = WHERE_INIT;
1119
1120 p = skip_var_one(arg, FALSE);
1121 varlen = p - arg;
1122 name = vim_strnsave(arg, varlen);
1123 if (name == NULL)
1124 goto failed;
Bram Moolenaarce93d162023-01-30 21:12:34 +00001125 if (*skipwhite(p) == ':')
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001126 {
Bram Moolenaarce93d162023-01-30 21:12:34 +00001127 if (VIM_ISWHITE(*p))
1128 {
1129 semsg(_(e_no_white_space_allowed_before_colon_str), p);
1130 goto failed;
1131 }
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001132 p = skipwhite(p + 1);
1133 lhs_type = parse_type(&p, cctx->ctx_type_list, TRUE);
Yegappan Lakshmanan062bb6b2023-12-16 14:46:40 +01001134 if (lhs_type == NULL)
1135 goto failed;
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001136 }
1137
1138 if (get_var_dest(name, &dest, CMD_for, &opt_flags,
1139 &vimvaridx, &type, cctx) == FAIL)
1140 goto failed;
1141 if (dest != dest_local)
1142 {
1143 if (generate_store_var(cctx, dest, opt_flags, vimvaridx,
Bram Moolenaard505d172022-12-18 21:42:55 +00001144 type, name, NULL) == FAIL)
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001145 goto failed;
1146 }
1147 else if (varlen == 1 && *arg == '_')
1148 {
1149 // Assigning to "_": drop the value.
1150 if (generate_instr_drop(cctx, ISN_DROP, 1) == NULL)
1151 goto failed;
1152 }
1153 else
1154 {
1155 // Script var is not supported.
1156 if (STRNCMP(name, "s:", 2) == 0)
1157 {
1158 emsg(_(e_cannot_use_script_variable_in_for_loop));
1159 goto failed;
1160 }
1161
1162 if (!valid_varname(arg, (int)varlen, FALSE))
1163 goto failed;
1164 if (lookup_local(arg, varlen, NULL, cctx) == OK)
1165 {
Bram Moolenaara9fa8c52023-01-02 18:10:04 +00001166 semsg(_(e_variable_already_declared_str), arg);
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001167 goto failed;
1168 }
1169
1170 // Reserve a variable to store "var".
LemonBoyc5d27442023-08-19 13:02:35 +02001171 if (var_list)
1172 {
1173 where.wt_index = idx + 1;
1174 where.wt_kind = WT_VARIABLE;
1175 }
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001176 if (lhs_type == &t_any)
1177 lhs_type = item_type;
1178 else if (item_type != &t_unknown
Bram Moolenaarc6951a72022-12-29 20:56:24 +00001179 && need_type_where(item_type, lhs_type, FALSE, -1,
Bram Moolenaara1c51952022-02-02 16:20:26 +00001180 where, cctx, FALSE, FALSE) == FAIL)
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001181 goto failed;
Bram Moolenaar159b2d52022-10-11 21:41:25 +01001182 var_lvar = reserve_local(cctx, arg, varlen, ASSIGN_FINAL,
Bram Moolenaar6586a012022-09-30 11:04:50 +01001183 lhs_type);
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001184 if (var_lvar == NULL)
1185 // out of memory or used as an argument
1186 goto failed;
1187
1188 if (semicolon && idx == var_count - 1)
1189 var_lvar->lv_type = vartype;
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001190 generate_STORE(cctx, ISN_STORE, var_lvar->lv_idx, NULL);
1191 }
1192
1193 if (*p == ',' || *p == ';')
1194 ++p;
1195 arg = skipwhite(p);
1196 vim_free(name);
1197 }
Bram Moolenaarb46c0832022-09-15 17:19:37 +01001198
Bram Moolenaar8abb5842022-09-17 12:39:58 +01001199 // remember the number of variables and closures, used for ENDLOOP
Bram Moolenaarcc341812022-09-19 15:54:34 +01001200 compile_fill_loop_info(&forscope->fs_loop_info, funcref_lvar_idx, cctx);
1201 forscope->fs_loop_info.li_depth = scope->se_loop_depth - 1;
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001202 }
1203
1204 return arg_end;
1205
1206failed:
1207 vim_free(name);
1208 drop_scope(cctx);
1209 return NULL;
1210}
1211
1212/*
Bram Moolenaar8abb5842022-09-17 12:39:58 +01001213 * Used when ending a loop of :for and :while: Generate an ISN_ENDLOOP
1214 * instruction if any variable was declared that could be used by a new
1215 * closure.
Bram Moolenaarb46c0832022-09-15 17:19:37 +01001216 */
1217 static int
Bram Moolenaar8abb5842022-09-17 12:39:58 +01001218compile_loop_end(loop_info_T *loop_info, cctx_T *cctx)
Bram Moolenaarb46c0832022-09-15 17:19:37 +01001219{
Bram Moolenaar8abb5842022-09-17 12:39:58 +01001220 if (cctx->ctx_locals.ga_len > loop_info->li_local_count
1221 && cctx->ctx_closure_count > loop_info->li_closure_count)
Bram Moolenaarcc341812022-09-19 15:54:34 +01001222 return generate_ENDLOOP(cctx, loop_info);
Bram Moolenaarb46c0832022-09-15 17:19:37 +01001223 return OK;
1224}
1225
1226/*
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001227 * compile "endfor"
1228 */
1229 char_u *
1230compile_endfor(char_u *arg, cctx_T *cctx)
1231{
1232 garray_T *instr = &cctx->ctx_instr;
1233 scope_T *scope = cctx->ctx_scope;
1234 forscope_T *forscope;
1235 isn_T *isn;
1236
1237 if (misplaced_cmdmod(cctx))
1238 return NULL;
1239
1240 if (scope == NULL || scope->se_type != FOR_SCOPE)
1241 {
Bram Moolenaar436b5ad2021-12-31 22:49:24 +00001242 emsg(_(e_endfor_without_for));
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001243 return NULL;
1244 }
1245 forscope = &scope->se_u.se_for;
1246 cctx->ctx_scope = scope->se_outer;
1247 if (cctx->ctx_skip != SKIP_YES)
1248 {
Bram Moolenaarb46c0832022-09-15 17:19:37 +01001249 // Handle the case that any local variables were declared that might be
1250 // used in a closure.
Bram Moolenaar8abb5842022-09-17 12:39:58 +01001251 if (compile_loop_end(&forscope->fs_loop_info, cctx) == FAIL)
Bram Moolenaarb46c0832022-09-15 17:19:37 +01001252 return NULL;
1253
Bram Moolenaara275f2c2022-10-11 20:04:09 +01001254 unwind_locals(cctx, scope->se_local_count, FALSE);
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001255
1256 // At end of ":for" scope jump back to the FOR instruction.
1257 generate_JUMP(cctx, JUMP_ALWAYS, forscope->fs_top_label);
1258
1259 // Fill in the "end" label in the FOR statement so it can jump here.
Bram Moolenaar2b4ecc22022-01-02 14:08:18 +00001260 // In debug mode an ISN_DEBUG was inserted.
1261 isn = ((isn_T *)instr->ga_data) + forscope->fs_top_label
1262 + (cctx->ctx_compile_type == CT_DEBUG ? 1 : 0);
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001263 isn->isn_arg.forloop.for_end = instr->ga_len;
1264
1265 // Fill in the "end" label any BREAK statements
1266 compile_fill_jump_to_end(&forscope->fs_end_label, instr->ga_len, cctx);
1267
1268 // Below the ":for" scope drop the "expr" list from the stack.
1269 if (generate_instr_drop(cctx, ISN_DROP, 1) == NULL)
1270 return NULL;
1271 }
1272
1273 vim_free(scope);
1274
1275 return arg;
1276}
1277
1278/*
1279 * compile "while expr"
1280 *
1281 * Produces instructions:
Bram Moolenaarb46c0832022-09-15 17:19:37 +01001282 * top: EVAL expr Push result of "expr"
1283 * WHILE funcref-idx end Jump if false
1284 * ... body ...
1285 * ENDLOOP funcref-idx off count only if closure uses local var
1286 * JUMP top Jump back to repeat
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001287 * end:
1288 *
1289 */
1290 char_u *
1291compile_while(char_u *arg, cctx_T *cctx)
1292{
Bram Moolenaarb46c0832022-09-15 17:19:37 +01001293 char_u *p = arg;
1294 scope_T *scope;
1295 whilescope_T *whilescope;
1296 lvar_T *funcref_lvar;
Bram Moolenaarcc341812022-09-19 15:54:34 +01001297 int funcref_lvar_idx;
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001298
1299 scope = new_scope(cctx, WHILE_SCOPE);
1300 if (scope == NULL)
1301 return NULL;
Bram Moolenaarcc341812022-09-19 15:54:34 +01001302 if (scope->se_loop_depth == MAX_LOOP_DEPTH)
1303 {
1304 emsg(_(e_loop_nesting_too_deep));
1305 return NULL;
1306 }
1307 ++scope->se_loop_depth;
Bram Moolenaarb46c0832022-09-15 17:19:37 +01001308 whilescope = &scope->se_u.se_while;
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001309
1310 // "endwhile" jumps back here, one before when profiling or using cmdmods
Bram Moolenaarb46c0832022-09-15 17:19:37 +01001311 whilescope->ws_top_label = current_instr_idx(cctx);
1312
1313 // Reserve a variable to store ec_funcrefs.ga_len, used in ISN_ENDLOOP.
1314 // It is not used when no closures are encountered, we don't know yet.
Bram Moolenaar6586a012022-09-30 11:04:50 +01001315 funcref_lvar = reserve_local(cctx, (char_u *)"", 0, ASSIGN_VAR, &t_number);
Bram Moolenaarb46c0832022-09-15 17:19:37 +01001316 if (funcref_lvar == NULL)
1317 {
1318 drop_scope(cctx);
1319 return NULL; // out of memory
1320 }
Bram Moolenaarcc341812022-09-19 15:54:34 +01001321 // get the index before a following reserve_local() makes the lval invalid
1322 funcref_lvar_idx = funcref_lvar->lv_idx;
Bram Moolenaar8abb5842022-09-17 12:39:58 +01001323
1324 // remember the number of variables and closures, used for ENDLOOP
Bram Moolenaarcc341812022-09-19 15:54:34 +01001325 compile_fill_loop_info(&whilescope->ws_loop_info, funcref_lvar_idx, cctx);
1326 whilescope->ws_loop_info.li_depth = scope->se_loop_depth - 1;
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001327
1328 // compile "expr"
1329 if (compile_expr0(&p, cctx) == FAIL)
1330 return NULL;
1331
1332 if (!ends_excmd2(arg, skipwhite(p)))
1333 {
Bram Moolenaar74409f62022-01-01 15:58:22 +00001334 semsg(_(e_trailing_characters_str), p);
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001335 return NULL;
1336 }
1337
1338 if (cctx->ctx_skip != SKIP_YES)
1339 {
1340 if (bool_on_stack(cctx) == FAIL)
1341 return FAIL;
1342
1343 // CMDMOD_REV must come before the jump
1344 generate_undo_cmdmods(cctx);
1345
1346 // "while_end" is set when ":endwhile" is found
Bram Moolenaarb46c0832022-09-15 17:19:37 +01001347 if (compile_jump_to_end(&whilescope->ws_end_label,
Bram Moolenaarcc341812022-09-19 15:54:34 +01001348 JUMP_WHILE_FALSE, funcref_lvar_idx, cctx) == FAIL)
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001349 return FAIL;
1350 }
1351
1352 return p;
1353}
1354
1355/*
1356 * compile "endwhile"
1357 */
1358 char_u *
1359compile_endwhile(char_u *arg, cctx_T *cctx)
1360{
1361 scope_T *scope = cctx->ctx_scope;
1362 garray_T *instr = &cctx->ctx_instr;
1363
1364 if (misplaced_cmdmod(cctx))
1365 return NULL;
1366 if (scope == NULL || scope->se_type != WHILE_SCOPE)
1367 {
Bram Moolenaar436b5ad2021-12-31 22:49:24 +00001368 emsg(_(e_endwhile_without_while));
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001369 return NULL;
1370 }
1371 cctx->ctx_scope = scope->se_outer;
1372 if (cctx->ctx_skip != SKIP_YES)
1373 {
Bram Moolenaarb46c0832022-09-15 17:19:37 +01001374 whilescope_T *whilescope = &scope->se_u.se_while;
1375
1376 // Handle the case that any local variables were declared that might be
1377 // used in a closure.
Bram Moolenaar8abb5842022-09-17 12:39:58 +01001378 if (compile_loop_end(&whilescope->ws_loop_info, cctx) == FAIL)
Bram Moolenaarb46c0832022-09-15 17:19:37 +01001379 return NULL;
1380
Bram Moolenaara275f2c2022-10-11 20:04:09 +01001381 unwind_locals(cctx, scope->se_local_count, FALSE);
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001382
1383#ifdef FEAT_PROFILE
1384 // count the endwhile before jumping
1385 may_generate_prof_end(cctx, cctx->ctx_lnum);
1386#endif
1387
1388 // At end of ":for" scope jump back to the FOR instruction.
1389 generate_JUMP(cctx, JUMP_ALWAYS, scope->se_u.se_while.ws_top_label);
1390
1391 // Fill in the "end" label in the WHILE statement so it can jump here.
1392 // And in any jumps for ":break"
1393 compile_fill_jump_to_end(&scope->se_u.se_while.ws_end_label,
1394 instr->ga_len, cctx);
1395 }
1396
1397 vim_free(scope);
1398
1399 return arg;
1400}
1401
1402/*
Bram Moolenaar8fa745e2022-09-16 19:04:24 +01001403 * Get the current information about variables declared inside a loop.
Bram Moolenaarcc341812022-09-19 15:54:34 +01001404 * Returns TRUE if there are any and fills "lvi".
Bram Moolenaar8fa745e2022-09-16 19:04:24 +01001405 */
Bram Moolenaarcc341812022-09-19 15:54:34 +01001406 int
1407get_loop_var_info(cctx_T *cctx, loopvarinfo_T *lvi)
Bram Moolenaar8fa745e2022-09-16 19:04:24 +01001408{
1409 scope_T *scope = cctx->ctx_scope;
Bram Moolenaarcc341812022-09-19 15:54:34 +01001410 int prev_local_count = 0;
Bram Moolenaar8fa745e2022-09-16 19:04:24 +01001411
Bram Moolenaarcc341812022-09-19 15:54:34 +01001412 CLEAR_POINTER(lvi);
1413 for (;;)
Bram Moolenaar8fa745e2022-09-16 19:04:24 +01001414 {
Bram Moolenaarcc341812022-09-19 15:54:34 +01001415 loop_info_T *loopinfo;
1416 int cur_local_last;
1417 int start_local_count;
1418
1419 while (scope != NULL && scope->se_type != WHILE_SCOPE
1420 && scope->se_type != FOR_SCOPE)
1421 scope = scope->se_outer;
1422 if (scope == NULL)
1423 break;
1424
1425 if (scope->se_type == WHILE_SCOPE)
1426 {
1427 loopinfo = &scope->se_u.se_while.ws_loop_info;
1428 // :while reserves one variable for funcref count
1429 cur_local_last = loopinfo->li_local_count - 1;
1430 }
1431 else
1432 {
1433 loopinfo = &scope->se_u.se_for.fs_loop_info;
1434 // :for reserves three variable: loop count, funcref count and loop
1435 // var
1436 cur_local_last = loopinfo->li_local_count - 3;
1437 }
1438
1439 start_local_count = loopinfo->li_local_count;
1440 if (cctx->ctx_locals.ga_len > start_local_count)
1441 {
1442 lvi->lvi_loop[loopinfo->li_depth].var_idx =
1443 (short)start_local_count;
1444 lvi->lvi_loop[loopinfo->li_depth].var_count =
1445 (short)(cctx->ctx_locals.ga_len - start_local_count
1446 - prev_local_count);
1447 if (lvi->lvi_depth == 0)
1448 lvi->lvi_depth = loopinfo->li_depth + 1;
1449 }
1450
1451 scope = scope->se_outer;
1452 prev_local_count = cctx->ctx_locals.ga_len - cur_local_last;
Bram Moolenaar8fa745e2022-09-16 19:04:24 +01001453 }
Bram Moolenaarcc341812022-09-19 15:54:34 +01001454 return lvi->lvi_depth > 0;
Bram Moolenaar8fa745e2022-09-16 19:04:24 +01001455}
1456
1457/*
Bram Moolenaarcc341812022-09-19 15:54:34 +01001458 * Get the index of the variable "idx" in a loop, if any.
Bram Moolenaar8fa745e2022-09-16 19:04:24 +01001459 */
Bram Moolenaarcc341812022-09-19 15:54:34 +01001460 void
1461get_loop_var_idx(cctx_T *cctx, int idx, lvar_T *lvar)
Bram Moolenaar8fa745e2022-09-16 19:04:24 +01001462{
Bram Moolenaarcc341812022-09-19 15:54:34 +01001463 loopvarinfo_T lvi;
Bram Moolenaar8fa745e2022-09-16 19:04:24 +01001464
Bram Moolenaarcc341812022-09-19 15:54:34 +01001465 lvar->lv_loop_depth = -1;
1466 lvar->lv_loop_idx = -1;
1467 if (get_loop_var_info(cctx, &lvi))
1468 {
1469 int depth;
1470
1471 for (depth = lvi.lvi_depth - 1; depth >= 0; --depth)
1472 if (idx >= lvi.lvi_loop[depth].var_idx
1473 && idx < lvi.lvi_loop[depth].var_idx
1474 + lvi.lvi_loop[depth].var_count)
1475 {
1476 lvar->lv_loop_depth = depth;
1477 lvar->lv_loop_idx = lvi.lvi_loop[depth].var_idx;
1478 return;
1479 }
1480 }
Bram Moolenaar8fa745e2022-09-16 19:04:24 +01001481}
1482
1483/*
Bram Moolenaar8abb5842022-09-17 12:39:58 +01001484 * Common for :break, :continue and :return
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001485 */
Bram Moolenaar8abb5842022-09-17 12:39:58 +01001486 static int
1487compile_find_scope(
1488 int *loop_label, // where to jump to or NULL
1489 endlabel_T ***el, // end label or NULL
1490 int *try_scopes, // :try scopes encountered or NULL
1491 char *error, // error to use when no scope found
1492 cctx_T *cctx)
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001493{
1494 scope_T *scope = cctx->ctx_scope;
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001495
1496 for (;;)
1497 {
1498 if (scope == NULL)
1499 {
Bram Moolenaar8abb5842022-09-17 12:39:58 +01001500 if (error != NULL)
1501 emsg(_(error));
1502 return FAIL;
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001503 }
1504 if (scope->se_type == FOR_SCOPE)
1505 {
Bram Moolenaar8abb5842022-09-17 12:39:58 +01001506 if (compile_loop_end(&scope->se_u.se_for.fs_loop_info, cctx)
1507 == FAIL)
1508 return FAIL;
1509 if (loop_label != NULL)
1510 *loop_label = scope->se_u.se_for.fs_top_label;
1511 if (el != NULL)
1512 *el = &scope->se_u.se_for.fs_end_label;
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001513 break;
1514 }
1515 if (scope->se_type == WHILE_SCOPE)
1516 {
Bram Moolenaar8abb5842022-09-17 12:39:58 +01001517 if (compile_loop_end(&scope->se_u.se_while.ws_loop_info, cctx)
1518 == FAIL)
1519 return FAIL;
1520 if (loop_label != NULL)
1521 *loop_label = scope->se_u.se_while.ws_top_label;
1522 if (el != NULL)
1523 *el = &scope->se_u.se_while.ws_end_label;
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001524 break;
1525 }
Bram Moolenaar8abb5842022-09-17 12:39:58 +01001526 if (try_scopes != NULL && scope->se_type == TRY_SCOPE)
1527 ++*try_scopes;
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001528 scope = scope->se_outer;
1529 }
Bram Moolenaar8abb5842022-09-17 12:39:58 +01001530 return OK;
1531}
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001532
Bram Moolenaar8abb5842022-09-17 12:39:58 +01001533/*
1534 * compile "continue"
1535 */
1536 char_u *
1537compile_continue(char_u *arg, cctx_T *cctx)
1538{
1539 int try_scopes = 0;
1540 int loop_label;
1541
1542 if (compile_find_scope(&loop_label, NULL, &try_scopes,
1543 e_continue_without_while_or_for, cctx) == FAIL)
1544 return NULL;
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001545 if (try_scopes > 0)
1546 // Inside one or more try/catch blocks we first need to jump to the
1547 // "finally" or "endtry" to cleanup.
1548 generate_TRYCONT(cctx, try_scopes, loop_label);
1549 else
1550 // Jump back to the FOR or WHILE instruction.
1551 generate_JUMP(cctx, JUMP_ALWAYS, loop_label);
1552
1553 return arg;
1554}
1555
1556/*
1557 * compile "break"
1558 */
1559 char_u *
1560compile_break(char_u *arg, cctx_T *cctx)
1561{
Bram Moolenaar873f8242022-03-10 21:53:44 +00001562 int try_scopes = 0;
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001563 endlabel_T **el;
1564
Bram Moolenaar8abb5842022-09-17 12:39:58 +01001565 if (compile_find_scope(NULL, &el, &try_scopes,
1566 e_break_without_while_or_for, cctx) == FAIL)
1567 return NULL;
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001568
Bram Moolenaar3f45d672023-02-27 22:06:51 +00001569 if (cctx->ctx_skip == SKIP_YES)
1570 return arg;
1571
Bram Moolenaar873f8242022-03-10 21:53:44 +00001572 if (try_scopes > 0)
1573 // Inside one or more try/catch blocks we first need to jump to the
1574 // "finally" or "endtry" to cleanup. Then come to the next JUMP
dundargocc57b5bc2022-11-02 13:30:51 +00001575 // instruction, which we don't know the index of yet.
Bram Moolenaar873f8242022-03-10 21:53:44 +00001576 generate_TRYCONT(cctx, try_scopes, cctx->ctx_instr.ga_len + 1);
1577
1578 // Jump to the end of the FOR or WHILE loop. The instruction index will be
1579 // filled in later.
Bram Moolenaarb46c0832022-09-15 17:19:37 +01001580 if (compile_jump_to_end(el, JUMP_ALWAYS, 0, cctx) == FAIL)
Bram Moolenaar3f45d672023-02-27 22:06:51 +00001581 return NULL;
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001582
1583 return arg;
1584}
1585
1586/*
1587 * compile "{" start of block
1588 */
1589 char_u *
1590compile_block(char_u *arg, cctx_T *cctx)
1591{
1592 if (new_scope(cctx, BLOCK_SCOPE) == NULL)
1593 return NULL;
1594 return skipwhite(arg + 1);
1595}
1596
1597/*
1598 * compile end of block: drop one scope
1599 */
1600 void
1601compile_endblock(cctx_T *cctx)
1602{
1603 scope_T *scope = cctx->ctx_scope;
1604
1605 cctx->ctx_scope = scope->se_outer;
Bram Moolenaara275f2c2022-10-11 20:04:09 +01001606 unwind_locals(cctx, scope->se_local_count, TRUE);
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001607 vim_free(scope);
1608}
1609
1610/*
1611 * Compile "try".
1612 * Creates a new scope for the try-endtry, pointing to the first catch and
1613 * finally.
1614 * Creates another scope for the "try" block itself.
1615 * TRY instruction sets up exception handling at runtime.
1616 *
1617 * "try"
1618 * TRY -> catch1, -> finally push trystack entry
1619 * ... try block
1620 * "throw {exception}"
1621 * EVAL {exception}
1622 * THROW create exception
1623 * ... try block
1624 * " catch {expr}"
1625 * JUMP -> finally
1626 * catch1: PUSH exception
1627 * EVAL {expr}
1628 * MATCH
1629 * JUMP nomatch -> catch2
1630 * CATCH remove exception
1631 * ... catch block
1632 * " catch"
1633 * JUMP -> finally
1634 * catch2: CATCH remove exception
1635 * ... catch block
1636 * " finally"
1637 * finally:
1638 * ... finally block
1639 * " endtry"
1640 * ENDTRY pop trystack entry, may rethrow
1641 */
1642 char_u *
1643compile_try(char_u *arg, cctx_T *cctx)
1644{
1645 garray_T *instr = &cctx->ctx_instr;
1646 scope_T *try_scope;
1647 scope_T *scope;
1648
1649 if (misplaced_cmdmod(cctx))
1650 return NULL;
1651
1652 // scope that holds the jumps that go to catch/finally/endtry
1653 try_scope = new_scope(cctx, TRY_SCOPE);
1654 if (try_scope == NULL)
1655 return NULL;
1656
1657 if (cctx->ctx_skip != SKIP_YES)
1658 {
1659 isn_T *isn;
1660
1661 // "try_catch" is set when the first ":catch" is found or when no catch
1662 // is found and ":finally" is found.
1663 // "try_finally" is set when ":finally" is found
1664 // "try_endtry" is set when ":endtry" is found
1665 try_scope->se_u.se_try.ts_try_label = instr->ga_len;
1666 if ((isn = generate_instr(cctx, ISN_TRY)) == NULL)
1667 return NULL;
Bram Moolenaar0d807102021-12-21 09:42:09 +00001668 isn->isn_arg.tryref.try_ref = ALLOC_CLEAR_ONE(tryref_T);
1669 if (isn->isn_arg.tryref.try_ref == NULL)
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001670 return NULL;
1671 }
1672
1673 // scope for the try block itself
1674 scope = new_scope(cctx, BLOCK_SCOPE);
1675 if (scope == NULL)
1676 return NULL;
1677
1678 return arg;
1679}
1680
1681/*
1682 * Compile "catch {expr}".
1683 */
1684 char_u *
Dominique Pellé0268ff32024-07-28 21:12:20 +02001685compile_catch(char_u *arg, cctx_T *cctx)
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001686{
1687 scope_T *scope = cctx->ctx_scope;
1688 garray_T *instr = &cctx->ctx_instr;
1689 char_u *p;
1690 isn_T *isn;
1691
1692 if (misplaced_cmdmod(cctx))
1693 return NULL;
1694
1695 // end block scope from :try or :catch
1696 if (scope != NULL && scope->se_type == BLOCK_SCOPE)
1697 compile_endblock(cctx);
1698 scope = cctx->ctx_scope;
1699
1700 // Error if not in a :try scope
1701 if (scope == NULL || scope->se_type != TRY_SCOPE)
1702 {
Bram Moolenaar436b5ad2021-12-31 22:49:24 +00001703 emsg(_(e_catch_without_try));
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001704 return NULL;
1705 }
1706
Bram Moolenaar9d383f32023-05-14 21:38:12 +01001707 if (scope->se_u.se_try.ts_caught_all
1708 && !ignore_unreachable_code_for_testing)
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001709 {
1710 emsg(_(e_catch_unreachable_after_catch_all));
1711 return NULL;
1712 }
Bram Moolenaar53c29612022-01-12 16:18:18 +00001713 if (!cctx->ctx_had_return)
1714 scope->se_u.se_try.ts_no_return = TRUE;
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001715
1716 if (cctx->ctx_skip != SKIP_YES)
1717 {
1718#ifdef FEAT_PROFILE
1719 // the profile-start should be after the jump
1720 if (cctx->ctx_compile_type == CT_PROFILE
1721 && instr->ga_len > 0
1722 && ((isn_T *)instr->ga_data)[instr->ga_len - 1]
1723 .isn_type == ISN_PROF_START)
1724 --instr->ga_len;
1725#endif
1726 // Jump from end of previous block to :finally or :endtry
1727 if (compile_jump_to_end(&scope->se_u.se_try.ts_end_label,
Bram Moolenaarb46c0832022-09-15 17:19:37 +01001728 JUMP_ALWAYS, 0, cctx) == FAIL)
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001729 return NULL;
1730
1731 // End :try or :catch scope: set value in ISN_TRY instruction
1732 isn = ((isn_T *)instr->ga_data) + scope->se_u.se_try.ts_try_label;
Bram Moolenaar0d807102021-12-21 09:42:09 +00001733 if (isn->isn_arg.tryref.try_ref->try_catch == 0)
1734 isn->isn_arg.tryref.try_ref->try_catch = instr->ga_len;
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001735 if (scope->se_u.se_try.ts_catch_label != 0)
1736 {
1737 // Previous catch without match jumps here
1738 isn = ((isn_T *)instr->ga_data) + scope->se_u.se_try.ts_catch_label;
1739 isn->isn_arg.jump.jump_where = instr->ga_len;
1740 }
1741#ifdef FEAT_PROFILE
1742 if (cctx->ctx_compile_type == CT_PROFILE)
1743 {
1744 // a "throw" that jumps here needs to be counted
1745 generate_instr(cctx, ISN_PROF_END);
1746 // the "catch" is also counted
1747 generate_instr(cctx, ISN_PROF_START);
1748 }
1749#endif
1750 if (cctx->ctx_compile_type == CT_DEBUG)
1751 generate_instr_debug(cctx);
1752 }
1753
1754 p = skipwhite(arg);
1755 if (ends_excmd2(arg, p))
1756 {
1757 scope->se_u.se_try.ts_caught_all = TRUE;
1758 scope->se_u.se_try.ts_catch_label = 0;
1759 }
1760 else
1761 {
1762 char_u *end;
1763 char_u *pat;
1764 char_u *tofree = NULL;
1765 int dropped = 0;
1766 int len;
1767
1768 // Push v:exception, push {expr} and MATCH
1769 generate_instr_type(cctx, ISN_PUSHEXC, &t_string);
1770
1771 end = skip_regexp_ex(p + 1, *p, TRUE, &tofree, &dropped, NULL);
1772 if (*end != *p)
1773 {
1774 semsg(_(e_separator_mismatch_str), p);
1775 vim_free(tofree);
Bram Moolenaar54969f42022-02-07 13:56:44 +00001776 return NULL;
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001777 }
1778 if (tofree == NULL)
1779 len = (int)(end - (p + 1));
1780 else
1781 len = (int)(end - tofree);
1782 pat = vim_strnsave(tofree == NULL ? p + 1 : tofree, len);
1783 vim_free(tofree);
1784 p += len + 2 + dropped;
1785 if (pat == NULL)
Bram Moolenaar54969f42022-02-07 13:56:44 +00001786 return NULL;
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001787 if (generate_PUSHS(cctx, &pat) == FAIL)
Bram Moolenaar54969f42022-02-07 13:56:44 +00001788 return NULL;
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001789
1790 if (generate_COMPARE(cctx, EXPR_MATCH, FALSE) == FAIL)
1791 return NULL;
1792
1793 scope->se_u.se_try.ts_catch_label = instr->ga_len;
1794 if (generate_JUMP(cctx, JUMP_IF_FALSE, 0) == FAIL)
1795 return NULL;
1796 }
1797
1798 if (cctx->ctx_skip != SKIP_YES && generate_instr(cctx, ISN_CATCH) == NULL)
1799 return NULL;
1800
1801 if (new_scope(cctx, BLOCK_SCOPE) == NULL)
1802 return NULL;
1803 return p;
1804}
1805
1806 char_u *
1807compile_finally(char_u *arg, cctx_T *cctx)
1808{
1809 scope_T *scope = cctx->ctx_scope;
1810 garray_T *instr = &cctx->ctx_instr;
1811 isn_T *isn;
1812 int this_instr;
1813
1814 if (misplaced_cmdmod(cctx))
1815 return NULL;
1816
1817 // end block scope from :try or :catch
1818 if (scope != NULL && scope->se_type == BLOCK_SCOPE)
1819 compile_endblock(cctx);
1820 scope = cctx->ctx_scope;
1821
1822 // Error if not in a :try scope
1823 if (scope == NULL || scope->se_type != TRY_SCOPE)
1824 {
Bram Moolenaar436b5ad2021-12-31 22:49:24 +00001825 emsg(_(e_finally_without_try));
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001826 return NULL;
1827 }
1828
1829 if (cctx->ctx_skip != SKIP_YES)
1830 {
1831 // End :catch or :finally scope: set value in ISN_TRY instruction
1832 isn = ((isn_T *)instr->ga_data) + scope->se_u.se_try.ts_try_label;
Bram Moolenaar0d807102021-12-21 09:42:09 +00001833 if (isn->isn_arg.tryref.try_ref->try_finally != 0)
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001834 {
Bram Moolenaar436b5ad2021-12-31 22:49:24 +00001835 emsg(_(e_multiple_finally));
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001836 return NULL;
1837 }
1838
1839 this_instr = instr->ga_len;
1840#ifdef FEAT_PROFILE
1841 if (cctx->ctx_compile_type == CT_PROFILE
1842 && ((isn_T *)instr->ga_data)[this_instr - 1]
1843 .isn_type == ISN_PROF_START)
1844 {
1845 // jump to the profile start of the "finally"
1846 --this_instr;
1847
1848 // jump to the profile end above it
1849 if (this_instr > 0 && ((isn_T *)instr->ga_data)[this_instr - 1]
1850 .isn_type == ISN_PROF_END)
1851 --this_instr;
1852 }
1853#endif
1854
1855 // Fill in the "end" label in jumps at the end of the blocks.
1856 compile_fill_jump_to_end(&scope->se_u.se_try.ts_end_label,
1857 this_instr, cctx);
1858
1859 // If there is no :catch then an exception jumps to :finally.
Bram Moolenaar0d807102021-12-21 09:42:09 +00001860 if (isn->isn_arg.tryref.try_ref->try_catch == 0)
1861 isn->isn_arg.tryref.try_ref->try_catch = this_instr;
1862 isn->isn_arg.tryref.try_ref->try_finally = this_instr;
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001863 if (scope->se_u.se_try.ts_catch_label != 0)
1864 {
1865 // Previous catch without match jumps here
1866 isn = ((isn_T *)instr->ga_data) + scope->se_u.se_try.ts_catch_label;
1867 isn->isn_arg.jump.jump_where = this_instr;
1868 scope->se_u.se_try.ts_catch_label = 0;
1869 }
Bram Moolenaar53c29612022-01-12 16:18:18 +00001870 scope->se_u.se_try.ts_has_finally = TRUE;
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001871 if (generate_instr(cctx, ISN_FINALLY) == NULL)
1872 return NULL;
1873 }
1874
1875 return arg;
1876}
1877
1878 char_u *
1879compile_endtry(char_u *arg, cctx_T *cctx)
1880{
1881 scope_T *scope = cctx->ctx_scope;
1882 garray_T *instr = &cctx->ctx_instr;
1883 isn_T *try_isn;
1884
1885 if (misplaced_cmdmod(cctx))
1886 return NULL;
1887
1888 // end block scope from :catch or :finally
1889 if (scope != NULL && scope->se_type == BLOCK_SCOPE)
1890 compile_endblock(cctx);
1891 scope = cctx->ctx_scope;
1892
1893 // Error if not in a :try scope
1894 if (scope == NULL || scope->se_type != TRY_SCOPE)
1895 {
1896 if (scope == NULL)
Bram Moolenaar436b5ad2021-12-31 22:49:24 +00001897 emsg(_(e_endtry_without_try));
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001898 else if (scope->se_type == WHILE_SCOPE)
Bram Moolenaar1a992222021-12-31 17:25:48 +00001899 emsg(_(e_missing_endwhile));
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001900 else if (scope->se_type == FOR_SCOPE)
Bram Moolenaar1a992222021-12-31 17:25:48 +00001901 emsg(_(e_missing_endfor));
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001902 else
Bram Moolenaar1a992222021-12-31 17:25:48 +00001903 emsg(_(e_missing_endif));
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001904 return NULL;
1905 }
1906
1907 try_isn = ((isn_T *)instr->ga_data) + scope->se_u.se_try.ts_try_label;
1908 if (cctx->ctx_skip != SKIP_YES)
1909 {
Bram Moolenaar0d807102021-12-21 09:42:09 +00001910 if (try_isn->isn_arg.tryref.try_ref->try_catch == 0
1911 && try_isn->isn_arg.tryref.try_ref->try_finally == 0)
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001912 {
1913 emsg(_(e_missing_catch_or_finally));
1914 return NULL;
1915 }
1916
1917#ifdef FEAT_PROFILE
1918 if (cctx->ctx_compile_type == CT_PROFILE
1919 && ((isn_T *)instr->ga_data)[instr->ga_len - 1]
1920 .isn_type == ISN_PROF_START)
1921 // move the profile start after "endtry" so that it's not counted when
1922 // the exception is rethrown.
1923 --instr->ga_len;
1924#endif
1925
1926 // Fill in the "end" label in jumps at the end of the blocks, if not
1927 // done by ":finally".
1928 compile_fill_jump_to_end(&scope->se_u.se_try.ts_end_label,
1929 instr->ga_len, cctx);
1930
1931 if (scope->se_u.se_try.ts_catch_label != 0)
1932 {
1933 // Last catch without match jumps here
1934 isn_T *isn = ((isn_T *)instr->ga_data)
1935 + scope->se_u.se_try.ts_catch_label;
1936 isn->isn_arg.jump.jump_where = instr->ga_len;
1937 }
1938 }
1939
Bram Moolenaar53c29612022-01-12 16:18:18 +00001940 // If there is a finally clause that ends in return then we will return.
1941 // If one of the blocks didn't end in "return" or we did not catch all
1942 // exceptions reset the had_return flag.
1943 if (!(scope->se_u.se_try.ts_has_finally && cctx->ctx_had_return)
1944 && (scope->se_u.se_try.ts_no_return
1945 || !scope->se_u.se_try.ts_caught_all))
1946 cctx->ctx_had_return = FALSE;
1947
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001948 compile_endblock(cctx);
1949
1950 if (cctx->ctx_skip != SKIP_YES)
1951 {
1952 // End :catch or :finally scope: set instruction index in ISN_TRY
1953 // instruction
Bram Moolenaar0d807102021-12-21 09:42:09 +00001954 try_isn->isn_arg.tryref.try_ref->try_endtry = instr->ga_len;
Bram Moolenaarfe154992022-03-22 20:42:12 +00001955 if (generate_instr(cctx, ISN_ENDTRY) == NULL)
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001956 return NULL;
1957#ifdef FEAT_PROFILE
1958 if (cctx->ctx_compile_type == CT_PROFILE)
1959 generate_instr(cctx, ISN_PROF_START);
1960#endif
1961 }
1962 return arg;
1963}
1964
1965/*
1966 * compile "throw {expr}"
1967 */
1968 char_u *
Dominique Pellé0268ff32024-07-28 21:12:20 +02001969compile_throw(char_u *arg, cctx_T *cctx)
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001970{
1971 char_u *p = skipwhite(arg);
1972
1973 if (compile_expr0(&p, cctx) == FAIL)
1974 return NULL;
1975 if (cctx->ctx_skip == SKIP_YES)
1976 return p;
Yegappan Lakshmananbce51d92024-04-15 19:19:52 +02001977 if (may_generate_2STRING(-1, TOSTRING_NONE, cctx) == FAIL)
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001978 return NULL;
1979 if (generate_instr_drop(cctx, ISN_THROW, 1) == NULL)
1980 return NULL;
1981
1982 return p;
1983}
1984
Bram Moolenaar1d84f762022-09-03 21:35:53 +01001985/*
1986 * Compile an expression or function call.
1987 */
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001988 char_u *
1989compile_eval(char_u *arg, cctx_T *cctx)
1990{
1991 char_u *p = arg;
1992 int name_only;
1993 long lnum = SOURCING_LNUM;
1994
1995 // find_ex_command() will consider a variable name an expression, assuming
1996 // that something follows on the next line. Check that something actually
1997 // follows, otherwise it's probably a misplaced command.
1998 name_only = cmd_is_name_only(arg);
1999
2000 if (compile_expr0(&p, cctx) == FAIL)
2001 return NULL;
2002
2003 if (name_only && lnum == SOURCING_LNUM)
2004 {
2005 semsg(_(e_expression_without_effect_str), arg);
2006 return NULL;
2007 }
2008
2009 // drop the result
2010 generate_instr_drop(cctx, ISN_DROP, 1);
2011
2012 return skipwhite(p);
2013}
2014
2015/*
Bram Moolenaarc572ad52022-09-08 20:49:22 +01002016 * Get the local variable index for deferred function calls.
2017 * Reserve it when not done already.
2018 * Returns zero for failure.
2019 */
2020 int
2021get_defer_var_idx(cctx_T *cctx)
2022{
2023 dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data)
2024 + cctx->ctx_ufunc->uf_dfunc_idx;
2025 if (dfunc->df_defer_var_idx == 0)
2026 {
2027 lvar_T *lvar = reserve_local(cctx, (char_u *)"@defer@", 7,
2028 TRUE, &t_list_any);
2029 if (lvar == NULL)
2030 return 0;
2031 dfunc->df_defer_var_idx = lvar->lv_idx + 1;
2032 }
2033 return dfunc->df_defer_var_idx;
2034}
2035
2036/*
Bram Moolenaar1d84f762022-09-03 21:35:53 +01002037 * Compile "defer func(arg)".
2038 */
2039 char_u *
2040compile_defer(char_u *arg_start, cctx_T *cctx)
2041{
Bram Moolenaar16900322022-09-08 19:51:45 +01002042 char_u *paren;
Bram Moolenaar1d84f762022-09-03 21:35:53 +01002043 char_u *arg = arg_start;
2044 int argcount = 0;
Bram Moolenaar806a2732022-09-04 15:40:36 +01002045 int defer_var_idx;
Yegappan Lakshmanan38ce1a72023-12-18 08:58:29 +01002046 type_T *type = NULL;
Bram Moolenaar1d84f762022-09-03 21:35:53 +01002047 int func_idx;
2048
2049 // Get a funcref for the function name.
2050 // TODO: better way to find the "(".
Bram Moolenaar16900322022-09-08 19:51:45 +01002051 paren = vim_strchr(arg, '(');
2052 if (paren == NULL)
Bram Moolenaar1d84f762022-09-03 21:35:53 +01002053 {
2054 semsg(_(e_missing_parenthesis_str), arg);
2055 return NULL;
2056 }
Bram Moolenaar16900322022-09-08 19:51:45 +01002057 *paren = NUL;
Bram Moolenaar1d84f762022-09-03 21:35:53 +01002058 func_idx = find_internal_func(arg);
2059 if (func_idx >= 0)
2060 // TODO: better type
2061 generate_PUSHFUNC(cctx, (char_u *)internal_func_name(func_idx),
2062 &t_func_any, FALSE);
Yegappan Lakshmananf3eac692023-10-17 11:00:45 +02002063 else if (compile_expr0(&arg, cctx) == FAIL)
2064 return NULL;
Bram Moolenaar16900322022-09-08 19:51:45 +01002065 *paren = '(';
Bram Moolenaar1d84f762022-09-03 21:35:53 +01002066
2067 // check for function type
Yegappan Lakshmanana185a312023-12-16 14:36:08 +01002068 if (cctx->ctx_skip != SKIP_YES)
Bram Moolenaar1d84f762022-09-03 21:35:53 +01002069 {
Yegappan Lakshmanana185a312023-12-16 14:36:08 +01002070 type = get_type_on_stack(cctx, 0);
2071 if (type->tt_type != VAR_FUNC)
2072 {
2073 emsg(_(e_function_name_required));
2074 return NULL;
2075 }
Bram Moolenaar1d84f762022-09-03 21:35:53 +01002076 }
2077
2078 // compile the arguments
Bram Moolenaar16900322022-09-08 19:51:45 +01002079 arg = skipwhite(paren + 1);
Bram Moolenaar1d84f762022-09-03 21:35:53 +01002080 if (compile_arguments(&arg, cctx, &argcount, CA_NOT_SPECIAL) == FAIL)
2081 return NULL;
2082
Yegappan Lakshmanana185a312023-12-16 14:36:08 +01002083 if (cctx->ctx_skip != SKIP_YES)
Bram Moolenaar16900322022-09-08 19:51:45 +01002084 {
Yegappan Lakshmanana185a312023-12-16 14:36:08 +01002085 if (func_idx >= 0)
2086 {
2087 type2_T *argtypes = NULL;
2088 type2_T shuffled_argtypes[MAX_FUNC_ARGS];
Bram Moolenaar16900322022-09-08 19:51:45 +01002089
Yegappan Lakshmanana185a312023-12-16 14:36:08 +01002090 if (check_internal_func_args(cctx, func_idx, argcount, FALSE,
2091 &argtypes, shuffled_argtypes) == FAIL)
2092 return NULL;
2093 }
2094 else if (check_func_args_from_type(cctx, type, argcount, TRUE,
2095 arg_start) == FAIL)
2096 return NULL;
2097
2098 defer_var_idx = get_defer_var_idx(cctx);
2099 if (defer_var_idx == 0)
2100 return NULL;
2101 if (generate_DEFER(cctx, defer_var_idx - 1, argcount) == FAIL)
Bram Moolenaar16900322022-09-08 19:51:45 +01002102 return NULL;
2103 }
Bram Moolenaar1d84f762022-09-03 21:35:53 +01002104
2105 return skipwhite(arg);
2106}
2107
2108/*
Bram Moolenaardc7c3662021-12-20 15:04:29 +00002109 * compile "echo expr"
2110 * compile "echomsg expr"
2111 * compile "echoerr expr"
2112 * compile "echoconsole expr"
Bram Moolenaarbdc09a12022-10-07 14:31:45 +01002113 * compile "echowindow expr" - may have cmd_count set
Bram Moolenaardc7c3662021-12-20 15:04:29 +00002114 * compile "execute expr"
2115 */
2116 char_u *
Bram Moolenaar9b994112022-12-25 15:59:25 +00002117compile_mult_expr(
2118 char_u *arg,
2119 int cmdidx,
2120 long cmd_count UNUSED,
2121 cctx_T *cctx)
Bram Moolenaardc7c3662021-12-20 15:04:29 +00002122{
2123 char_u *p = arg;
2124 char_u *prev = arg;
2125 char_u *expr_start;
2126 int count = 0;
2127 int start_ctx_lnum = cctx->ctx_lnum;
Bram Moolenaardc7c3662021-12-20 15:04:29 +00002128 type_T *type;
Bram Moolenaarbdc09a12022-10-07 14:31:45 +01002129 int r = OK;
Bram Moolenaardc7c3662021-12-20 15:04:29 +00002130
2131 for (;;)
2132 {
2133 if (ends_excmd2(prev, p))
2134 break;
2135 expr_start = p;
2136 if (compile_expr0(&p, cctx) == FAIL)
2137 return NULL;
2138
2139 if (cctx->ctx_skip != SKIP_YES)
2140 {
2141 // check for non-void type
Bram Moolenaar078a4612022-01-04 15:17:03 +00002142 type = get_type_on_stack(cctx, 0);
Bram Moolenaardc7c3662021-12-20 15:04:29 +00002143 if (type->tt_type == VAR_VOID)
2144 {
2145 semsg(_(e_expression_does_not_result_in_value_str), expr_start);
2146 return NULL;
2147 }
2148 }
2149
2150 ++count;
2151 prev = p;
2152 p = skipwhite(p);
2153 }
2154
2155 if (count > 0)
2156 {
2157 long save_lnum = cctx->ctx_lnum;
2158
2159 // Use the line number where the command started.
2160 cctx->ctx_lnum = start_ctx_lnum;
2161
2162 if (cmdidx == CMD_echo || cmdidx == CMD_echon)
Bram Moolenaarbdc09a12022-10-07 14:31:45 +01002163 r = generate_ECHO(cctx, cmdidx == CMD_echo, count);
Bram Moolenaardc7c3662021-12-20 15:04:29 +00002164 else if (cmdidx == CMD_execute)
Bram Moolenaarbdc09a12022-10-07 14:31:45 +01002165 r = generate_MULT_EXPR(cctx, ISN_EXECUTE, count);
Bram Moolenaardc7c3662021-12-20 15:04:29 +00002166 else if (cmdidx == CMD_echomsg)
Bram Moolenaarbdc09a12022-10-07 14:31:45 +01002167 r = generate_MULT_EXPR(cctx, ISN_ECHOMSG, count);
Bram Moolenaar7d7ad7b2022-09-01 16:00:53 +01002168#ifdef HAS_MESSAGE_WINDOW
2169 else if (cmdidx == CMD_echowindow)
Bram Moolenaarbdc09a12022-10-07 14:31:45 +01002170 r = generate_ECHOWINDOW(cctx, count, cmd_count);
Bram Moolenaar7d7ad7b2022-09-01 16:00:53 +01002171#endif
Bram Moolenaardc7c3662021-12-20 15:04:29 +00002172 else if (cmdidx == CMD_echoconsole)
Bram Moolenaarbdc09a12022-10-07 14:31:45 +01002173 r = generate_MULT_EXPR(cctx, ISN_ECHOCONSOLE, count);
Bram Moolenaardc7c3662021-12-20 15:04:29 +00002174 else
Bram Moolenaarbdc09a12022-10-07 14:31:45 +01002175 r = generate_MULT_EXPR(cctx, ISN_ECHOERR, count);
Bram Moolenaardc7c3662021-12-20 15:04:29 +00002176
2177 cctx->ctx_lnum = save_lnum;
2178 }
Bram Moolenaarbdc09a12022-10-07 14:31:45 +01002179 return r == OK ? p : NULL;
Bram Moolenaardc7c3662021-12-20 15:04:29 +00002180}
2181
2182/*
2183 * If "eap" has a range that is not a constant generate an ISN_RANGE
2184 * instruction to compute it and return OK.
2185 * Otherwise return FAIL, the caller must deal with any range.
2186 */
2187 static int
2188compile_variable_range(exarg_T *eap, cctx_T *cctx)
2189{
2190 char_u *range_end = skip_range(eap->cmd, TRUE, NULL);
2191 char_u *p = skipdigits(eap->cmd);
2192
2193 if (p == range_end)
2194 return FAIL;
2195 return generate_RANGE(cctx, vim_strnsave(eap->cmd, range_end - eap->cmd));
2196}
2197
2198/*
2199 * :put r
2200 * :put ={expr}
64-bitmane08f10a2025-03-18 22:14:34 +01002201 * or if fixindent == TRUE
2202 * :iput r
2203 * :iput ={expr}
Bram Moolenaardc7c3662021-12-20 15:04:29 +00002204 */
2205 char_u *
64-bitmane08f10a2025-03-18 22:14:34 +01002206compile_put(char_u *arg, exarg_T *eap, cctx_T *cctx, int fixindent)
Bram Moolenaardc7c3662021-12-20 15:04:29 +00002207{
2208 char_u *line = arg;
2209 linenr_T lnum;
2210 char *errormsg;
2211 int above = eap->forceit;
2212
2213 eap->regname = *line;
2214
2215 if (eap->regname == '=')
2216 {
Bram Moolenaard0b7bfa2022-03-12 14:51:16 +00002217 char_u *p = skipwhite(line + 1);
Bram Moolenaardc7c3662021-12-20 15:04:29 +00002218
2219 if (compile_expr0(&p, cctx) == FAIL)
2220 return NULL;
2221 line = p;
2222 }
2223 else if (eap->regname != NUL)
2224 ++line;
2225
2226 if (compile_variable_range(eap, cctx) == OK)
2227 {
2228 lnum = above ? LNUM_VARIABLE_RANGE_ABOVE : LNUM_VARIABLE_RANGE;
2229 }
2230 else
2231 {
2232 // Either no range or a number.
2233 // "errormsg" will not be set because the range is ADDR_LINES.
2234 if (parse_cmd_address(eap, &errormsg, FALSE) == FAIL)
2235 // cannot happen
2236 return NULL;
2237 if (eap->addr_count == 0)
2238 lnum = -1;
2239 else
2240 lnum = eap->line2;
2241 if (above)
2242 --lnum;
2243 }
2244
64-bitmane08f10a2025-03-18 22:14:34 +01002245 generate_PUT(cctx, eap->regname, lnum, fixindent);
2246
Bram Moolenaardc7c3662021-12-20 15:04:29 +00002247 return line;
2248}
2249
2250/*
2251 * A command that is not compiled, execute with legacy code.
2252 */
2253 char_u *
2254compile_exec(char_u *line_arg, exarg_T *eap, cctx_T *cctx)
2255{
2256 char_u *line = line_arg;
2257 char_u *p;
2258 int has_expr = FALSE;
2259 char_u *nextcmd = (char_u *)"";
2260 char_u *tofree = NULL;
2261 char_u *cmd_arg = NULL;
2262
2263 if (cctx->ctx_skip == SKIP_YES)
2264 goto theend;
2265
2266 // If there was a prececing command modifier, drop it and include it in the
2267 // EXEC command.
2268 if (cctx->ctx_has_cmdmod)
2269 {
2270 garray_T *instr = &cctx->ctx_instr;
2271 isn_T *isn = ((isn_T *)instr->ga_data) + instr->ga_len - 1;
2272
2273 if (isn->isn_type == ISN_CMDMOD)
2274 {
2275 vim_regfree(isn->isn_arg.cmdmod.cf_cmdmod
2276 ->cmod_filter_regmatch.regprog);
2277 vim_free(isn->isn_arg.cmdmod.cf_cmdmod);
2278 --instr->ga_len;
2279 cctx->ctx_has_cmdmod = FALSE;
2280 }
2281 }
2282
2283 if (eap->cmdidx >= 0 && eap->cmdidx < CMD_SIZE)
2284 {
2285 long argt = eap->argt;
2286 int usefilter = FALSE;
2287
2288 has_expr = argt & (EX_XFILE | EX_EXPAND);
2289
2290 // If the command can be followed by a bar, find the bar and truncate
2291 // it, so that the following command can be compiled.
2292 // The '|' is overwritten with a NUL, it is put back below.
2293 if ((eap->cmdidx == CMD_write || eap->cmdidx == CMD_read)
2294 && *eap->arg == '!')
2295 // :w !filter or :r !filter or :r! filter
2296 usefilter = TRUE;
2297 if ((argt & EX_TRLBAR) && !usefilter)
2298 {
2299 eap->argt = argt;
Bram Moolenaarac485062022-03-23 19:45:01 +00002300 separate_nextcmd(eap, TRUE);
Bram Moolenaardc7c3662021-12-20 15:04:29 +00002301 if (eap->nextcmd != NULL)
2302 nextcmd = eap->nextcmd;
2303 }
2304 else if (eap->cmdidx == CMD_wincmd)
2305 {
2306 p = eap->arg;
2307 if (*p != NUL)
2308 ++p;
2309 if (*p == 'g' || *p == Ctrl_G)
2310 ++p;
2311 p = skipwhite(p);
2312 if (*p == '|')
2313 {
2314 *p = NUL;
2315 nextcmd = p + 1;
2316 }
2317 }
2318 else if (eap->cmdidx == CMD_command || eap->cmdidx == CMD_autocmd)
2319 {
2320 // If there is a trailing '{' read lines until the '}'
2321 p = eap->arg + STRLEN(eap->arg) - 1;
2322 while (p > eap->arg && VIM_ISWHITE(*p))
2323 --p;
2324 if (*p == '{')
2325 {
2326 exarg_T ea;
Bram Moolenaar62628d92022-02-25 21:10:53 +00002327 int flags = 0; // unused
Bram Moolenaardc7c3662021-12-20 15:04:29 +00002328 int start_lnum = SOURCING_LNUM;
2329
2330 CLEAR_FIELD(ea);
2331 ea.arg = eap->arg;
2332 fill_exarg_from_cctx(&ea, cctx);
2333 (void)may_get_cmd_block(&ea, p, &tofree, &flags);
2334 if (tofree != NULL)
2335 {
2336 *p = NUL;
2337 line = concat_str(line, tofree);
2338 if (line == NULL)
2339 goto theend;
2340 vim_free(tofree);
2341 tofree = line;
2342 SOURCING_LNUM = start_lnum;
2343 }
2344 }
2345 }
2346 }
2347
2348 if (eap->cmdidx == CMD_syntax && STRNCMP(eap->arg, "include ", 8) == 0)
2349 {
2350 // expand filename in "syntax include [@group] filename"
2351 has_expr = TRUE;
2352 eap->arg = skipwhite(eap->arg + 7);
2353 if (*eap->arg == '@')
2354 eap->arg = skiptowhite(eap->arg);
2355 }
2356
2357 if ((eap->cmdidx == CMD_global || eap->cmdidx == CMD_vglobal)
2358 && STRLEN(eap->arg) > 4)
2359 {
2360 int delim = *eap->arg;
2361
2362 p = skip_regexp_ex(eap->arg + 1, delim, TRUE, NULL, NULL, NULL);
2363 if (*p == delim)
2364 cmd_arg = p + 1;
2365 }
2366
2367 if (eap->cmdidx == CMD_folddoopen || eap->cmdidx == CMD_folddoclosed)
2368 cmd_arg = eap->arg;
2369
2370 if (cmd_arg != NULL)
2371 {
2372 exarg_T nea;
2373
2374 CLEAR_FIELD(nea);
2375 nea.cmd = cmd_arg;
2376 p = find_ex_command(&nea, NULL, lookup_scriptitem, NULL);
2377 if (nea.cmdidx < CMD_SIZE)
2378 {
2379 has_expr = excmd_get_argt(nea.cmdidx) & (EX_XFILE | EX_EXPAND);
2380 if (has_expr)
2381 eap->arg = skiptowhite(eap->arg);
2382 }
2383 }
2384
2385 if (has_expr && (p = (char_u *)strstr((char *)eap->arg, "`=")) != NULL)
2386 {
2387 int count = 0;
2388 char_u *start = skipwhite(line);
2389
2390 // :cmd xxx`=expr1`yyy`=expr2`zzz
2391 // PUSHS ":cmd xxx"
2392 // eval expr1
2393 // PUSHS "yyy"
2394 // eval expr2
2395 // PUSHS "zzz"
2396 // EXECCONCAT 5
2397 for (;;)
2398 {
2399 if (p > start)
2400 {
2401 char_u *val = vim_strnsave(start, p - start);
2402
2403 generate_PUSHS(cctx, &val);
2404 ++count;
2405 }
2406 p += 2;
2407 if (compile_expr0(&p, cctx) == FAIL)
2408 return NULL;
Yegappan Lakshmananbce51d92024-04-15 19:19:52 +02002409 may_generate_2STRING(-1, TOSTRING_TOLERANT, cctx);
Bram Moolenaardc7c3662021-12-20 15:04:29 +00002410 ++count;
2411 p = skipwhite(p);
2412 if (*p != '`')
2413 {
2414 emsg(_(e_missing_backtick));
2415 return NULL;
2416 }
2417 start = p + 1;
2418
2419 p = (char_u *)strstr((char *)start, "`=");
2420 if (p == NULL)
2421 {
2422 if (*skipwhite(start) != NUL)
2423 {
2424 char_u *val = vim_strsave(start);
2425
2426 generate_PUSHS(cctx, &val);
2427 ++count;
2428 }
2429 break;
2430 }
2431 }
2432 generate_EXECCONCAT(cctx, count);
2433 }
2434 else
2435 generate_EXEC_copy(cctx, ISN_EXEC, line);
2436
2437theend:
2438 if (*nextcmd != NUL)
2439 {
2440 // the parser expects a pointer to the bar, put it back
2441 --nextcmd;
2442 *nextcmd = '|';
2443 }
2444 vim_free(tofree);
2445
2446 return nextcmd;
2447}
2448
2449/*
2450 * A script command with heredoc, e.g.
2451 * ruby << EOF
2452 * command
2453 * EOF
2454 * Has been turned into one long line with NL characters by
2455 * get_function_body():
2456 * ruby << EOF<NL> command<NL>EOF
2457 */
2458 char_u *
2459compile_script(char_u *line, cctx_T *cctx)
2460{
2461 if (cctx->ctx_skip != SKIP_YES)
2462 {
2463 isn_T *isn;
2464
2465 if ((isn = generate_instr(cctx, ISN_EXEC_SPLIT)) == NULL)
2466 return NULL;
2467 isn->isn_arg.string = vim_strsave(line);
2468 }
2469 return (char_u *)"";
2470}
2471
2472
2473/*
2474 * :s/pat/repl/
2475 */
2476 char_u *
2477compile_substitute(char_u *arg, exarg_T *eap, cctx_T *cctx)
2478{
2479 char_u *cmd = eap->arg;
2480 char_u *expr = (char_u *)strstr((char *)cmd, "\\=");
2481
2482 if (expr != NULL)
2483 {
2484 int delimiter = *cmd++;
2485
2486 // There is a \=expr, find it in the substitute part.
2487 cmd = skip_regexp_ex(cmd, delimiter, magic_isset(), NULL, NULL, NULL);
2488 if (cmd[0] == delimiter && cmd[1] == '\\' && cmd[2] == '=')
2489 {
2490 garray_T save_ga = cctx->ctx_instr;
2491 char_u *end;
2492 int expr_res;
2493 int trailing_error;
2494 int instr_count;
2495 isn_T *instr;
2496 isn_T *isn;
2497
2498 cmd += 3;
2499 end = skip_substitute(cmd, delimiter);
2500
2501 // Temporarily reset the list of instructions so that the jump
2502 // labels are correct.
2503 cctx->ctx_instr.ga_len = 0;
2504 cctx->ctx_instr.ga_maxlen = 0;
2505 cctx->ctx_instr.ga_data = NULL;
2506 expr_res = compile_expr0(&cmd, cctx);
2507 if (end[-1] == NUL)
2508 end[-1] = delimiter;
2509 cmd = skipwhite(cmd);
2510 trailing_error = *cmd != delimiter && *cmd != NUL;
2511
2512 if (expr_res == FAIL || trailing_error
2513 || GA_GROW_FAILS(&cctx->ctx_instr, 1))
2514 {
2515 if (trailing_error)
Bram Moolenaar74409f62022-01-01 15:58:22 +00002516 semsg(_(e_trailing_characters_str), cmd);
Bram Moolenaardc7c3662021-12-20 15:04:29 +00002517 clear_instr_ga(&cctx->ctx_instr);
2518 cctx->ctx_instr = save_ga;
2519 return NULL;
2520 }
2521
2522 // Move the generated instructions into the ISN_SUBSTITUTE
2523 // instructions, then restore the list of instructions before
2524 // adding the ISN_SUBSTITUTE instruction.
2525 instr_count = cctx->ctx_instr.ga_len;
2526 instr = cctx->ctx_instr.ga_data;
2527 instr[instr_count].isn_type = ISN_FINISH;
2528
2529 cctx->ctx_instr = save_ga;
2530 if ((isn = generate_instr(cctx, ISN_SUBSTITUTE)) == NULL)
2531 {
2532 int idx;
2533
2534 for (idx = 0; idx < instr_count; ++idx)
2535 delete_instr(instr + idx);
2536 vim_free(instr);
2537 return NULL;
2538 }
2539 isn->isn_arg.subs.subs_cmd = vim_strsave(arg);
2540 isn->isn_arg.subs.subs_instr = instr;
2541
2542 // skip over flags
2543 if (*end == '&')
2544 ++end;
2545 while (ASCII_ISALPHA(*end) || *end == '#')
2546 ++end;
2547 return end;
2548 }
2549 }
2550
2551 return compile_exec(arg, eap, cctx);
2552}
2553
2554 char_u *
2555compile_redir(char_u *line, exarg_T *eap, cctx_T *cctx)
2556{
2557 char_u *arg = eap->arg;
2558 lhs_T *lhs = &cctx->ctx_redir_lhs;
2559
2560 if (lhs->lhs_name != NULL)
2561 {
2562 if (STRNCMP(arg, "END", 3) == 0)
2563 {
Bram Moolenaar3558afe2022-10-13 16:12:57 +01002564 if (cctx->ctx_skip != SKIP_YES)
Bram Moolenaardc7c3662021-12-20 15:04:29 +00002565 {
Bram Moolenaar3558afe2022-10-13 16:12:57 +01002566 if (lhs->lhs_append)
2567 {
2568 // First load the current variable value.
2569 if (compile_load_lhs_with_index(lhs, lhs->lhs_whole,
Bram Moolenaardc7c3662021-12-20 15:04:29 +00002570 cctx) == FAIL)
Bram Moolenaar3558afe2022-10-13 16:12:57 +01002571 return NULL;
2572 }
Bram Moolenaardc7c3662021-12-20 15:04:29 +00002573
Bram Moolenaar3558afe2022-10-13 16:12:57 +01002574 // Gets the redirected text and put it on the stack, then store
2575 // it in the variable.
2576 generate_instr_type(cctx, ISN_REDIREND, &t_string);
Bram Moolenaardc7c3662021-12-20 15:04:29 +00002577
Bram Moolenaar3558afe2022-10-13 16:12:57 +01002578 if (lhs->lhs_append)
2579 generate_CONCAT(cctx, 2);
Bram Moolenaardc7c3662021-12-20 15:04:29 +00002580
Bram Moolenaar3558afe2022-10-13 16:12:57 +01002581 if (lhs->lhs_has_index)
2582 {
2583 // Use the info in "lhs" to store the value at the index in
2584 // the list or dict.
2585 if (compile_assign_unlet(lhs->lhs_whole, lhs, TRUE,
Bram Moolenaardc7c3662021-12-20 15:04:29 +00002586 &t_string, cctx) == FAIL)
Bram Moolenaar3558afe2022-10-13 16:12:57 +01002587 return NULL;
2588 }
2589 else if (generate_store_lhs(cctx, lhs, -1, FALSE) == FAIL)
Bram Moolenaardc7c3662021-12-20 15:04:29 +00002590 return NULL;
Bram Moolenaardc7c3662021-12-20 15:04:29 +00002591
Bram Moolenaar3558afe2022-10-13 16:12:57 +01002592 VIM_CLEAR(lhs->lhs_name);
2593 VIM_CLEAR(lhs->lhs_whole);
2594 }
Bram Moolenaardc7c3662021-12-20 15:04:29 +00002595 return arg + 3;
2596 }
2597 emsg(_(e_cannot_nest_redir));
2598 return NULL;
2599 }
2600
2601 if (arg[0] == '=' && arg[1] == '>')
2602 {
2603 int append = FALSE;
2604
2605 // redirect to a variable is compiled
2606 arg += 2;
2607 if (*arg == '>')
2608 {
2609 ++arg;
2610 append = TRUE;
2611 }
2612 arg = skipwhite(arg);
2613
2614 if (compile_assign_lhs(arg, lhs, CMD_redir,
Bram Moolenaar97f8c102022-04-02 19:43:57 +01002615 FALSE, FALSE, FALSE, 1, cctx) == FAIL)
Bram Moolenaardc7c3662021-12-20 15:04:29 +00002616 return NULL;
Bram Moolenaarc6951a72022-12-29 20:56:24 +00002617 if (need_type(&t_string, lhs->lhs_member_type, FALSE,
Bram Moolenaardc7c3662021-12-20 15:04:29 +00002618 -1, 0, cctx, FALSE, FALSE) == FAIL)
2619 return NULL;
Bram Moolenaar3558afe2022-10-13 16:12:57 +01002620 if (cctx->ctx_skip == SKIP_YES)
Bram Moolenaardc7c3662021-12-20 15:04:29 +00002621 {
Bram Moolenaar3558afe2022-10-13 16:12:57 +01002622 VIM_CLEAR(lhs->lhs_name);
2623 }
2624 else
2625 {
2626 generate_instr(cctx, ISN_REDIRSTART);
2627 lhs->lhs_append = append;
2628 if (lhs->lhs_has_index)
2629 {
2630 lhs->lhs_whole = vim_strnsave(arg, lhs->lhs_varlen_total);
2631 if (lhs->lhs_whole == NULL)
2632 return NULL;
2633 }
Bram Moolenaardc7c3662021-12-20 15:04:29 +00002634 }
2635
2636 return arg + lhs->lhs_varlen_total;
2637 }
2638
2639 // other redirects are handled like at script level
2640 return compile_exec(line, eap, cctx);
2641}
2642
2643#if defined(FEAT_QUICKFIX) || defined(PROTO)
2644 char_u *
2645compile_cexpr(char_u *line, exarg_T *eap, cctx_T *cctx)
2646{
2647 isn_T *isn;
2648 char_u *p;
2649
2650 isn = generate_instr(cctx, ISN_CEXPR_AUCMD);
2651 if (isn == NULL)
2652 return NULL;
2653 isn->isn_arg.number = eap->cmdidx;
2654
2655 p = eap->arg;
2656 if (compile_expr0(&p, cctx) == FAIL)
2657 return NULL;
2658
2659 isn = generate_instr(cctx, ISN_CEXPR_CORE);
2660 if (isn == NULL)
2661 return NULL;
2662 isn->isn_arg.cexpr.cexpr_ref = ALLOC_ONE(cexprref_T);
2663 if (isn->isn_arg.cexpr.cexpr_ref == NULL)
2664 return NULL;
2665 isn->isn_arg.cexpr.cexpr_ref->cer_cmdidx = eap->cmdidx;
2666 isn->isn_arg.cexpr.cexpr_ref->cer_forceit = eap->forceit;
2667 isn->isn_arg.cexpr.cexpr_ref->cer_cmdline = vim_strsave(skipwhite(line));
2668
2669 return p;
2670}
2671#endif
2672
2673/*
2674 * Compile "return [expr]".
2675 * When "legacy" is TRUE evaluate [expr] with legacy syntax
2676 */
2677 char_u *
2678compile_return(char_u *arg, int check_return_type, int legacy, cctx_T *cctx)
2679{
2680 char_u *p = arg;
Bram Moolenaardc7c3662021-12-20 15:04:29 +00002681 type_T *stack_type;
2682
mityu500c4442022-12-02 18:12:05 +00002683 if (*p != NUL && *p != '|' && *p != '\n'
2684 && (legacy || !vim9_comment_start(p)))
Bram Moolenaardc7c3662021-12-20 15:04:29 +00002685 {
Bram Moolenaar0bfa8492022-01-22 12:27:04 +00002686 // For a lambda, "return expr" is always used, also when "expr" results
2687 // in a void.
2688 if (cctx->ctx_ufunc->uf_ret_type->tt_type == VAR_VOID
2689 && (cctx->ctx_ufunc->uf_flags & FC_LAMBDA) == 0)
Bram Moolenaaref7aadb2022-01-18 18:46:07 +00002690 {
2691 emsg(_(e_returning_value_in_function_without_return_type));
2692 return NULL;
2693 }
Bram Moolenaardc7c3662021-12-20 15:04:29 +00002694 if (legacy)
2695 {
2696 int save_flags = cmdmod.cmod_flags;
2697
2698 generate_LEGACY_EVAL(cctx, p);
Bram Moolenaarc6951a72022-12-29 20:56:24 +00002699 if (need_type(&t_any, cctx->ctx_ufunc->uf_ret_type, FALSE, -1,
Bram Moolenaardc7c3662021-12-20 15:04:29 +00002700 0, cctx, FALSE, FALSE) == FAIL)
2701 return NULL;
2702 cmdmod.cmod_flags |= CMOD_LEGACY;
2703 (void)skip_expr(&p, NULL);
2704 cmdmod.cmod_flags = save_flags;
2705 }
2706 else
2707 {
2708 // compile return argument into instructions
2709 if (compile_expr0(&p, cctx) == FAIL)
2710 return NULL;
2711 }
2712
2713 if (cctx->ctx_skip != SKIP_YES)
2714 {
2715 // "check_return_type" with uf_ret_type set to &t_unknown is used
2716 // for an inline function without a specified return type. Set the
2717 // return type here.
Bram Moolenaar078a4612022-01-04 15:17:03 +00002718 stack_type = get_type_on_stack(cctx, 0);
Ernie Raelb077b582023-12-14 20:11:44 +01002719 if (check_type_is_value(stack_type) == FAIL)
2720 return NULL;
Bram Moolenaardc7c3662021-12-20 15:04:29 +00002721 if ((check_return_type && (cctx->ctx_ufunc->uf_ret_type == NULL
Bram Moolenaar1a572e92022-03-15 12:28:10 +00002722 || cctx->ctx_ufunc->uf_ret_type == &t_unknown))
Bram Moolenaardc7c3662021-12-20 15:04:29 +00002723 || (!check_return_type
2724 && cctx->ctx_ufunc->uf_ret_type == &t_unknown))
2725 {
2726 cctx->ctx_ufunc->uf_ret_type = stack_type;
2727 }
2728 else
2729 {
Bram Moolenaarc6951a72022-12-29 20:56:24 +00002730 if (need_type(stack_type, cctx->ctx_ufunc->uf_ret_type, FALSE,
2731 -1, 0, cctx, FALSE, FALSE) == FAIL)
Bram Moolenaardc7c3662021-12-20 15:04:29 +00002732 return NULL;
2733 }
2734 }
2735 }
2736 else
2737 {
2738 // "check_return_type" cannot be TRUE, only used for a lambda which
2739 // always has an argument.
2740 if (cctx->ctx_ufunc->uf_ret_type->tt_type != VAR_VOID
2741 && cctx->ctx_ufunc->uf_ret_type->tt_type != VAR_UNKNOWN)
2742 {
2743 emsg(_(e_missing_return_value));
2744 return NULL;
2745 }
2746
Yegappan Lakshmanan1db15142023-09-19 20:34:05 +02002747 if (IS_CONSTRUCTOR_METHOD(cctx->ctx_ufunc))
Yegappan Lakshmanan6ac15442023-08-20 18:20:17 +02002748 {
2749 // For a class new() constructor, return an object of the class.
2750 generate_instr(cctx, ISN_RETURN_OBJECT);
2751 cctx->ctx_ufunc->uf_ret_type =
2752 &cctx->ctx_ufunc->uf_class->class_object_type;
2753 }
2754 else
2755 // No argument, return zero.
2756 generate_PUSHNR(cctx, 0);
Bram Moolenaardc7c3662021-12-20 15:04:29 +00002757 }
2758
Bram Moolenaar8abb5842022-09-17 12:39:58 +01002759 // may need ENDLOOP when inside a :for or :while loop
2760 if (compile_find_scope(NULL, NULL, NULL, NULL, cctx) == FAIL)
2761
Bram Moolenaardc7c3662021-12-20 15:04:29 +00002762 // Undo any command modifiers.
2763 generate_undo_cmdmods(cctx);
2764
2765 if (cctx->ctx_skip != SKIP_YES && generate_instr(cctx, ISN_RETURN) == NULL)
2766 return NULL;
2767
2768 // "return val | endif" is possible
2769 return skipwhite(p);
2770}
2771
2772/*
2773 * Check if the separator for a :global or :substitute command is OK.
2774 */
2775 int
2776check_global_and_subst(char_u *cmd, char_u *arg)
2777{
2778 if (arg == cmd + 1 && vim_strchr((char_u *)":-.", *arg) != NULL)
2779 {
2780 semsg(_(e_separator_not_supported_str), arg);
2781 return FAIL;
2782 }
2783 if (VIM_ISWHITE(cmd[1]))
2784 {
2785 semsg(_(e_no_white_space_allowed_before_separator_str), cmd);
2786 return FAIL;
2787 }
2788 return OK;
2789}
2790
2791
2792#endif // defined(FEAT_EVAL)