blob: cc2c0415837e74e2591773d72f81098f4b11dcb1 [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".
60 */
61 static void
62unwind_locals(cctx_T *cctx, int new_top)
63{
64 if (cctx->ctx_locals.ga_len > new_top)
65 {
66 int idx;
67 lvar_T *lvar;
68
69 for (idx = new_top; idx < cctx->ctx_locals.ga_len; ++idx)
70 {
71 lvar = ((lvar_T *)cctx->ctx_locals.ga_data) + idx;
72 vim_free(lvar->lv_name);
73 }
74 }
75 cctx->ctx_locals.ga_len = new_top;
76}
77
78/*
79 * Free all local variables.
80 */
81 void
82free_locals(cctx_T *cctx)
83{
84 unwind_locals(cctx, 0);
85 ga_clear(&cctx->ctx_locals);
86}
87
88
89/*
90 * Check if "name" can be "unlet".
91 */
92 int
93check_vim9_unlet(char_u *name)
94{
95 if (name[1] != ':' || vim_strchr((char_u *)"gwtb", *name) == NULL)
96 {
97 // "unlet s:var" is allowed in legacy script.
98 if (*name == 's' && !script_is_vim9())
99 return OK;
100 semsg(_(e_cannot_unlet_str), name);
101 return FAIL;
102 }
103 return OK;
104}
105
106/*
107 * Callback passed to ex_unletlock().
108 */
109 static int
110compile_unlet(
111 lval_T *lvp,
112 char_u *name_end,
113 exarg_T *eap,
114 int deep UNUSED,
115 void *coookie)
116{
117 cctx_T *cctx = coookie;
118 char_u *p = lvp->ll_name;
119 int cc = *name_end;
120 int ret = OK;
121
122 if (cctx->ctx_skip == SKIP_YES)
123 return OK;
124
125 *name_end = NUL;
126 if (*p == '$')
127 {
128 // :unlet $ENV_VAR
129 ret = generate_UNLET(cctx, ISN_UNLETENV, p + 1, eap->forceit);
130 }
131 else if (vim_strchr(p, '.') != NULL || vim_strchr(p, '[') != NULL)
132 {
133 lhs_T lhs;
134
135 // This is similar to assigning: lookup the list/dict, compile the
136 // idx/key. Then instead of storing the value unlet the item.
137 // unlet {list}[idx]
138 // unlet {dict}[key] dict.key
139 //
140 // Figure out the LHS type and other properties.
141 //
142 ret = compile_lhs(p, &lhs, CMD_unlet, FALSE, 0, cctx);
143
Bram Moolenaar2ef01d92022-01-06 21:38:11 +0000144 // Use the info in "lhs" to unlet the item at the index in the
145 // list or dict.
146 if (ret == OK)
Bram Moolenaardc7c3662021-12-20 15:04:29 +0000147 {
Bram Moolenaar2ef01d92022-01-06 21:38:11 +0000148 if (!lhs.lhs_has_index)
149 {
150 semsg(_(e_cannot_unlet_imported_item_str), p);
151 ret = FAIL;
152 }
153 else
154 ret = compile_assign_unlet(p, &lhs, FALSE, &t_void, cctx);
Bram Moolenaardc7c3662021-12-20 15:04:29 +0000155 }
156
157 vim_free(lhs.lhs_name);
158 }
159 else if (check_vim9_unlet(p) == FAIL)
160 {
161 ret = FAIL;
162 }
163 else
164 {
165 // Normal name. Only supports g:, w:, t: and b: namespaces.
166 ret = generate_UNLET(cctx, ISN_UNLET, p, eap->forceit);
167 }
168
169 *name_end = cc;
170 return ret;
171}
172
173/*
174 * Callback passed to ex_unletlock().
175 */
176 static int
177compile_lock_unlock(
178 lval_T *lvp,
179 char_u *name_end,
180 exarg_T *eap,
Bram Moolenaar70c43d82022-01-26 21:01:15 +0000181 int deep,
Bram Moolenaardc7c3662021-12-20 15:04:29 +0000182 void *coookie)
183{
184 cctx_T *cctx = coookie;
185 int cc = *name_end;
186 char_u *p = lvp->ll_name;
187 int ret = OK;
188 size_t len;
189 char_u *buf;
190 isntype_T isn = ISN_EXEC;
191
192 if (cctx->ctx_skip == SKIP_YES)
193 return OK;
194
195 // Cannot use :lockvar and :unlockvar on local variables.
196 if (p[1] != ':')
197 {
198 char_u *end = find_name_end(p, NULL, NULL, FNE_CHECK_START);
199
200 if (lookup_local(p, end - p, NULL, cctx) == OK)
201 {
202 char_u *s = p;
203
204 if (*end != '.' && *end != '[')
205 {
206 emsg(_(e_cannot_lock_unlock_local_variable));
207 return FAIL;
208 }
209
210 // For "d.member" put the local variable on the stack, it will be
211 // passed to ex_lockvar() indirectly.
212 if (compile_load(&s, end, cctx, FALSE, FALSE) == FAIL)
213 return FAIL;
214 isn = ISN_LOCKUNLOCK;
215 }
216 }
217
218 // Checking is done at runtime.
219 *name_end = NUL;
220 len = name_end - p + 20;
221 buf = alloc(len);
222 if (buf == NULL)
223 ret = FAIL;
224 else
225 {
Bram Moolenaare939f5e2022-01-26 21:32:59 +0000226 char *cmd = eap->cmdidx == CMD_lockvar ? "lockvar" : "unlockvar";
227
228 if (deep < 0)
229 vim_snprintf((char *)buf, len, "%s! %s", cmd, p);
230 else
231 vim_snprintf((char *)buf, len, "%s %d %s", cmd, deep, p);
Bram Moolenaardc7c3662021-12-20 15:04:29 +0000232 ret = generate_EXEC_copy(cctx, isn, buf);
233
234 vim_free(buf);
235 *name_end = cc;
236 }
237 return ret;
238}
239
240/*
241 * compile "unlet var", "lock var" and "unlock var"
242 * "arg" points to "var".
243 */
244 char_u *
245compile_unletlock(char_u *arg, exarg_T *eap, cctx_T *cctx)
246{
Bram Moolenaar70c43d82022-01-26 21:01:15 +0000247 int deep = 0;
248 char_u *p = arg;
249
250 if (eap->cmdidx != CMD_unlet)
251 {
252 if (eap->forceit)
253 deep = -1;
254 else if (vim_isdigit(*p))
255 {
256 deep = getdigits(&p);
257 p = skipwhite(p);
258 }
259 else
260 deep = 2;
261 }
262
263 ex_unletlock(eap, p, deep, GLV_NO_AUTOLOAD | GLV_COMPILING,
Bram Moolenaardc7c3662021-12-20 15:04:29 +0000264 eap->cmdidx == CMD_unlet ? compile_unlet : compile_lock_unlock,
265 cctx);
266 return eap->nextcmd == NULL ? (char_u *)"" : eap->nextcmd;
267}
268
269/*
270 * generate a jump to the ":endif"/":endfor"/":endwhile"/":finally"/":endtry".
271 */
272 static int
273compile_jump_to_end(endlabel_T **el, jumpwhen_T when, cctx_T *cctx)
274{
275 garray_T *instr = &cctx->ctx_instr;
276 endlabel_T *endlabel = ALLOC_CLEAR_ONE(endlabel_T);
277
278 if (endlabel == NULL)
279 return FAIL;
280 endlabel->el_next = *el;
281 *el = endlabel;
282 endlabel->el_end_label = instr->ga_len;
283
284 generate_JUMP(cctx, when, 0);
285 return OK;
286}
287
288 static void
289compile_fill_jump_to_end(endlabel_T **el, int jump_where, cctx_T *cctx)
290{
291 garray_T *instr = &cctx->ctx_instr;
292
293 while (*el != NULL)
294 {
295 endlabel_T *cur = (*el);
296 isn_T *isn;
297
298 isn = ((isn_T *)instr->ga_data) + cur->el_end_label;
299 isn->isn_arg.jump.jump_where = jump_where;
300 *el = cur->el_next;
301 vim_free(cur);
302 }
303}
304
305 static void
306compile_free_jump_to_end(endlabel_T **el)
307{
308 while (*el != NULL)
309 {
310 endlabel_T *cur = (*el);
311
312 *el = cur->el_next;
313 vim_free(cur);
314 }
315}
316
317/*
318 * Create a new scope and set up the generic items.
319 */
320 static scope_T *
321new_scope(cctx_T *cctx, scopetype_T type)
322{
323 scope_T *scope = ALLOC_CLEAR_ONE(scope_T);
324
325 if (scope == NULL)
326 return NULL;
327 scope->se_outer = cctx->ctx_scope;
328 cctx->ctx_scope = scope;
329 scope->se_type = type;
330 scope->se_local_count = cctx->ctx_locals.ga_len;
331 return scope;
332}
333
334/*
335 * Free the current scope and go back to the outer scope.
336 */
337 void
338drop_scope(cctx_T *cctx)
339{
340 scope_T *scope = cctx->ctx_scope;
341
342 if (scope == NULL)
343 {
344 iemsg("calling drop_scope() without a scope");
345 return;
346 }
347 cctx->ctx_scope = scope->se_outer;
348 switch (scope->se_type)
349 {
350 case IF_SCOPE:
351 compile_free_jump_to_end(&scope->se_u.se_if.is_end_label); break;
352 case FOR_SCOPE:
353 compile_free_jump_to_end(&scope->se_u.se_for.fs_end_label); break;
354 case WHILE_SCOPE:
355 compile_free_jump_to_end(&scope->se_u.se_while.ws_end_label); break;
356 case TRY_SCOPE:
357 compile_free_jump_to_end(&scope->se_u.se_try.ts_end_label); break;
358 case NO_SCOPE:
359 case BLOCK_SCOPE:
360 break;
361 }
362 vim_free(scope);
363}
364
365 static int
366misplaced_cmdmod(cctx_T *cctx)
367{
368 garray_T *instr = &cctx->ctx_instr;
369
370 if (cctx->ctx_has_cmdmod
371 && ((isn_T *)instr->ga_data)[instr->ga_len - 1].isn_type
372 == ISN_CMDMOD)
373 {
374 emsg(_(e_misplaced_command_modifier));
375 return TRUE;
376 }
377 return FALSE;
378}
379
380/*
381 * compile "if expr"
382 *
383 * "if expr" Produces instructions:
384 * EVAL expr Push result of "expr"
385 * JUMP_IF_FALSE end
386 * ... body ...
387 * end:
388 *
389 * "if expr | else" Produces instructions:
390 * EVAL expr Push result of "expr"
391 * JUMP_IF_FALSE else
392 * ... body ...
393 * JUMP_ALWAYS end
394 * else:
395 * ... body ...
396 * end:
397 *
398 * "if expr1 | elseif expr2 | else" Produces instructions:
399 * EVAL expr Push result of "expr"
400 * JUMP_IF_FALSE elseif
401 * ... body ...
402 * JUMP_ALWAYS end
403 * elseif:
404 * EVAL expr Push result of "expr"
405 * JUMP_IF_FALSE else
406 * ... body ...
407 * JUMP_ALWAYS end
408 * else:
409 * ... body ...
410 * end:
411 */
412 char_u *
413compile_if(char_u *arg, cctx_T *cctx)
414{
415 char_u *p = arg;
416 garray_T *instr = &cctx->ctx_instr;
417 int instr_count = instr->ga_len;
418 scope_T *scope;
419 skip_T skip_save = cctx->ctx_skip;
420 ppconst_T ppconst;
421
422 CLEAR_FIELD(ppconst);
423 if (compile_expr1(&p, cctx, &ppconst) == FAIL)
424 {
425 clear_ppconst(&ppconst);
426 return NULL;
427 }
428 if (!ends_excmd2(arg, skipwhite(p)))
429 {
Bram Moolenaar74409f62022-01-01 15:58:22 +0000430 semsg(_(e_trailing_characters_str), p);
Bram Moolenaardc7c3662021-12-20 15:04:29 +0000431 return NULL;
432 }
433 if (cctx->ctx_skip == SKIP_YES)
434 clear_ppconst(&ppconst);
435 else if (instr->ga_len == instr_count && ppconst.pp_used == 1)
436 {
437 int error = FALSE;
438 int v;
439
440 // The expression results in a constant.
441 v = tv_get_bool_chk(&ppconst.pp_tv[0], &error);
442 clear_ppconst(&ppconst);
443 if (error)
444 return NULL;
445 cctx->ctx_skip = v ? SKIP_NOT : SKIP_YES;
446 }
447 else
448 {
449 // Not a constant, generate instructions for the expression.
450 cctx->ctx_skip = SKIP_UNKNOWN;
451 if (generate_ppconst(cctx, &ppconst) == FAIL)
452 return NULL;
453 if (bool_on_stack(cctx) == FAIL)
454 return NULL;
455 }
456
457 // CMDMOD_REV must come before the jump
458 generate_undo_cmdmods(cctx);
459
460 scope = new_scope(cctx, IF_SCOPE);
461 if (scope == NULL)
462 return NULL;
463 scope->se_skip_save = skip_save;
464 // "is_had_return" will be reset if any block does not end in :return
465 scope->se_u.se_if.is_had_return = TRUE;
466
467 if (cctx->ctx_skip == SKIP_UNKNOWN)
468 {
469 // "where" is set when ":elseif", "else" or ":endif" is found
470 scope->se_u.se_if.is_if_label = instr->ga_len;
471 generate_JUMP(cctx, JUMP_IF_FALSE, 0);
472 }
473 else
474 scope->se_u.se_if.is_if_label = -1;
475
476#ifdef FEAT_PROFILE
477 if (cctx->ctx_compile_type == CT_PROFILE && cctx->ctx_skip == SKIP_YES
478 && skip_save != SKIP_YES)
479 {
480 // generated a profile start, need to generate a profile end, since it
481 // won't be done after returning
482 cctx->ctx_skip = SKIP_NOT;
483 generate_instr(cctx, ISN_PROF_END);
484 cctx->ctx_skip = SKIP_YES;
485 }
486#endif
487
488 return p;
489}
490
491 char_u *
492compile_elseif(char_u *arg, cctx_T *cctx)
493{
494 char_u *p = arg;
495 garray_T *instr = &cctx->ctx_instr;
496 int instr_count;
497 isn_T *isn;
498 scope_T *scope = cctx->ctx_scope;
499 ppconst_T ppconst;
500 skip_T save_skip = cctx->ctx_skip;
501
502 if (scope == NULL || scope->se_type != IF_SCOPE)
503 {
504 emsg(_(e_elseif_without_if));
505 return NULL;
506 }
507 unwind_locals(cctx, scope->se_local_count);
508 if (!cctx->ctx_had_return)
509 scope->se_u.se_if.is_had_return = FALSE;
510
511 if (cctx->ctx_skip == SKIP_NOT)
512 {
513 // previous block was executed, this one and following will not
514 cctx->ctx_skip = SKIP_YES;
515 scope->se_u.se_if.is_seen_skip_not = TRUE;
516 }
517 if (scope->se_u.se_if.is_seen_skip_not)
518 {
519 // A previous block was executed, skip over expression and bail out.
520 // Do not count the "elseif" for profiling and cmdmod
521 instr->ga_len = current_instr_idx(cctx);
522
523 skip_expr_cctx(&p, cctx);
524 return p;
525 }
526
527 if (cctx->ctx_skip == SKIP_UNKNOWN)
528 {
529 int moved_cmdmod = FALSE;
530 int saved_debug = FALSE;
531 isn_T debug_isn;
532
533 // Move any CMDMOD instruction to after the jump
534 if (((isn_T *)instr->ga_data)[instr->ga_len - 1].isn_type == ISN_CMDMOD)
535 {
536 if (GA_GROW_FAILS(instr, 1))
537 return NULL;
538 ((isn_T *)instr->ga_data)[instr->ga_len] =
539 ((isn_T *)instr->ga_data)[instr->ga_len - 1];
540 --instr->ga_len;
541 moved_cmdmod = TRUE;
542 }
543
544 // Remove the already generated ISN_DEBUG, it is written below the
545 // ISN_FOR instruction.
546 if (cctx->ctx_compile_type == CT_DEBUG && instr->ga_len > 0
547 && ((isn_T *)instr->ga_data)[instr->ga_len - 1]
548 .isn_type == ISN_DEBUG)
549 {
550 --instr->ga_len;
551 debug_isn = ((isn_T *)instr->ga_data)[instr->ga_len];
552 saved_debug = TRUE;
553 }
554
555 if (compile_jump_to_end(&scope->se_u.se_if.is_end_label,
556 JUMP_ALWAYS, cctx) == FAIL)
557 return NULL;
558 // previous "if" or "elseif" jumps here
559 isn = ((isn_T *)instr->ga_data) + scope->se_u.se_if.is_if_label;
560 isn->isn_arg.jump.jump_where = instr->ga_len;
561
562 if (moved_cmdmod)
563 ++instr->ga_len;
564
565 if (saved_debug)
566 {
567 // move the debug instruction here
568 if (GA_GROW_FAILS(instr, 1))
569 return NULL;
570 ((isn_T *)instr->ga_data)[instr->ga_len] = debug_isn;
571 ++instr->ga_len;
572 }
573 }
574
575 // compile "expr"; if we know it evaluates to FALSE skip the block
576 CLEAR_FIELD(ppconst);
577 if (cctx->ctx_skip == SKIP_YES)
578 {
579 cctx->ctx_skip = SKIP_UNKNOWN;
580#ifdef FEAT_PROFILE
581 if (cctx->ctx_compile_type == CT_PROFILE)
582 // the previous block was skipped, need to profile this line
583 generate_instr(cctx, ISN_PROF_START);
584#endif
585 if (cctx->ctx_compile_type == CT_DEBUG)
586 // the previous block was skipped, may want to debug this line
587 generate_instr_debug(cctx);
588 }
589
590 instr_count = instr->ga_len;
591 if (compile_expr1(&p, cctx, &ppconst) == FAIL)
592 {
593 clear_ppconst(&ppconst);
594 return NULL;
595 }
596 cctx->ctx_skip = save_skip;
597 if (!ends_excmd2(arg, skipwhite(p)))
598 {
599 clear_ppconst(&ppconst);
Bram Moolenaar74409f62022-01-01 15:58:22 +0000600 semsg(_(e_trailing_characters_str), p);
Bram Moolenaardc7c3662021-12-20 15:04:29 +0000601 return NULL;
602 }
603 if (scope->se_skip_save == SKIP_YES)
604 clear_ppconst(&ppconst);
605 else if (instr->ga_len == instr_count && ppconst.pp_used == 1)
606 {
607 int error = FALSE;
608 int v;
609
610 // The expression result is a constant.
611 v = tv_get_bool_chk(&ppconst.pp_tv[0], &error);
612 if (error)
613 {
614 clear_ppconst(&ppconst);
615 return NULL;
616 }
617 cctx->ctx_skip = v ? SKIP_NOT : SKIP_YES;
618 clear_ppconst(&ppconst);
619 scope->se_u.se_if.is_if_label = -1;
620 }
621 else
622 {
623 // Not a constant, generate instructions for the expression.
624 cctx->ctx_skip = SKIP_UNKNOWN;
625 if (generate_ppconst(cctx, &ppconst) == FAIL)
626 return NULL;
627 if (bool_on_stack(cctx) == FAIL)
628 return NULL;
629
630 // CMDMOD_REV must come before the jump
631 generate_undo_cmdmods(cctx);
632
633 // "where" is set when ":elseif", "else" or ":endif" is found
634 scope->se_u.se_if.is_if_label = instr->ga_len;
635 generate_JUMP(cctx, JUMP_IF_FALSE, 0);
636 }
637
638 return p;
639}
640
641 char_u *
642compile_else(char_u *arg, cctx_T *cctx)
643{
644 char_u *p = arg;
645 garray_T *instr = &cctx->ctx_instr;
646 isn_T *isn;
647 scope_T *scope = cctx->ctx_scope;
648
649 if (scope == NULL || scope->se_type != IF_SCOPE)
650 {
651 emsg(_(e_else_without_if));
652 return NULL;
653 }
654 unwind_locals(cctx, scope->se_local_count);
655 if (!cctx->ctx_had_return)
656 scope->se_u.se_if.is_had_return = FALSE;
657 scope->se_u.se_if.is_seen_else = TRUE;
658
659#ifdef FEAT_PROFILE
660 if (cctx->ctx_compile_type == CT_PROFILE)
661 {
662 if (cctx->ctx_skip == SKIP_NOT
663 && ((isn_T *)instr->ga_data)[instr->ga_len - 1]
664 .isn_type == ISN_PROF_START)
665 // the previous block was executed, do not count "else" for
666 // profiling
667 --instr->ga_len;
668 if (cctx->ctx_skip == SKIP_YES && !scope->se_u.se_if.is_seen_skip_not)
669 {
670 // the previous block was not executed, this one will, do count the
671 // "else" for profiling
672 cctx->ctx_skip = SKIP_NOT;
673 generate_instr(cctx, ISN_PROF_END);
674 generate_instr(cctx, ISN_PROF_START);
675 cctx->ctx_skip = SKIP_YES;
676 }
677 }
678#endif
679
680 if (!scope->se_u.se_if.is_seen_skip_not && scope->se_skip_save != SKIP_YES)
681 {
682 // jump from previous block to the end, unless the else block is empty
683 if (cctx->ctx_skip == SKIP_UNKNOWN)
684 {
685 if (!cctx->ctx_had_return
686 && compile_jump_to_end(&scope->se_u.se_if.is_end_label,
687 JUMP_ALWAYS, cctx) == FAIL)
688 return NULL;
689 }
690
691 if (cctx->ctx_skip == SKIP_UNKNOWN)
692 {
693 if (scope->se_u.se_if.is_if_label >= 0)
694 {
695 // previous "if" or "elseif" jumps here
696 isn = ((isn_T *)instr->ga_data) + scope->se_u.se_if.is_if_label;
697 isn->isn_arg.jump.jump_where = instr->ga_len;
698 scope->se_u.se_if.is_if_label = -1;
699 }
700 }
701
702 if (cctx->ctx_skip != SKIP_UNKNOWN)
703 cctx->ctx_skip = cctx->ctx_skip == SKIP_YES ? SKIP_NOT : SKIP_YES;
704 }
705
706 return p;
707}
708
709 char_u *
710compile_endif(char_u *arg, cctx_T *cctx)
711{
712 scope_T *scope = cctx->ctx_scope;
713 ifscope_T *ifscope;
714 garray_T *instr = &cctx->ctx_instr;
715 isn_T *isn;
716
717 if (misplaced_cmdmod(cctx))
718 return NULL;
719
720 if (scope == NULL || scope->se_type != IF_SCOPE)
721 {
722 emsg(_(e_endif_without_if));
723 return NULL;
724 }
725 ifscope = &scope->se_u.se_if;
726 unwind_locals(cctx, scope->se_local_count);
727 if (!cctx->ctx_had_return)
728 ifscope->is_had_return = FALSE;
729
730 if (scope->se_u.se_if.is_if_label >= 0)
731 {
732 // previous "if" or "elseif" jumps here
733 isn = ((isn_T *)instr->ga_data) + scope->se_u.se_if.is_if_label;
734 isn->isn_arg.jump.jump_where = instr->ga_len;
735 }
736 // Fill in the "end" label in jumps at the end of the blocks.
737 compile_fill_jump_to_end(&ifscope->is_end_label, instr->ga_len, cctx);
738
739#ifdef FEAT_PROFILE
740 // even when skipping we count the endif as executed, unless the block it's
741 // in is skipped
742 if (cctx->ctx_compile_type == CT_PROFILE && cctx->ctx_skip == SKIP_YES
743 && scope->se_skip_save != SKIP_YES)
744 {
745 cctx->ctx_skip = SKIP_NOT;
746 generate_instr(cctx, ISN_PROF_START);
747 }
748#endif
749 cctx->ctx_skip = scope->se_skip_save;
750
751 // If all the blocks end in :return and there is an :else then the
752 // had_return flag is set.
753 cctx->ctx_had_return = ifscope->is_had_return && ifscope->is_seen_else;
754
755 drop_scope(cctx);
756 return arg;
757}
758
759/*
760 * Compile "for var in expr":
761 *
762 * Produces instructions:
763 * PUSHNR -1
764 * STORE loop-idx Set index to -1
765 * EVAL expr result of "expr" on top of stack
766 * top: FOR loop-idx, end Increment index, use list on bottom of stack
767 * - if beyond end, jump to "end"
768 * - otherwise get item from list and push it
769 * STORE var Store item in "var"
770 * ... body ...
771 * JUMP top Jump back to repeat
772 * end: DROP Drop the result of "expr"
773 *
774 * Compile "for [var1, var2] in expr" - as above, but instead of "STORE var":
775 * UNPACK 2 Split item in 2
776 * STORE var1 Store item in "var1"
777 * STORE var2 Store item in "var2"
778 */
779 char_u *
780compile_for(char_u *arg_start, cctx_T *cctx)
781{
782 char_u *arg;
783 char_u *arg_end;
784 char_u *name = NULL;
785 char_u *p;
786 char_u *wp;
787 int var_count = 0;
788 int var_list = FALSE;
789 int semicolon = FALSE;
790 size_t varlen;
Bram Moolenaardc7c3662021-12-20 15:04:29 +0000791 garray_T *instr = &cctx->ctx_instr;
792 scope_T *scope;
793 lvar_T *loop_lvar; // loop iteration variable
794 lvar_T *var_lvar; // variable for "var"
795 type_T *vartype;
796 type_T *item_type = &t_any;
797 int idx;
798 int prev_lnum = cctx->ctx_prev_lnum;
799
800 p = skip_var_list(arg_start, TRUE, &var_count, &semicolon, FALSE);
801 if (p == NULL)
802 return NULL;
803 if (var_count == 0)
804 var_count = 1;
805 else
806 var_list = TRUE; // can also be a list of one variable
807
808 // consume "in"
809 wp = p;
810 if (may_get_next_line_error(wp, &p, cctx) == FAIL)
811 return NULL;
812 if (STRNCMP(p, "in", 2) != 0 || !IS_WHITE_OR_NUL(p[2]))
813 {
814 if (*p == ':' && wp != p)
815 semsg(_(e_no_white_space_allowed_before_colon_str), p);
816 else
Bram Moolenaar3a846e62022-01-01 16:21:00 +0000817 emsg(_(e_missing_in_after_for));
Bram Moolenaardc7c3662021-12-20 15:04:29 +0000818 return NULL;
819 }
820 wp = p + 2;
821 if (may_get_next_line_error(wp, &p, cctx) == FAIL)
822 return NULL;
823
Bram Moolenaar2b4ecc22022-01-02 14:08:18 +0000824 // Find the already generated ISN_DEBUG to get the line number for the
825 // instruction written below the ISN_FOR instruction.
Bram Moolenaardc7c3662021-12-20 15:04:29 +0000826 if (cctx->ctx_compile_type == CT_DEBUG && instr->ga_len > 0
827 && ((isn_T *)instr->ga_data)[instr->ga_len - 1]
828 .isn_type == ISN_DEBUG)
829 {
Bram Moolenaar2b4ecc22022-01-02 14:08:18 +0000830 prev_lnum = ((isn_T *)instr->ga_data)[instr->ga_len - 1]
Bram Moolenaardc7c3662021-12-20 15:04:29 +0000831 .isn_arg.debug.dbg_break_lnum;
832 }
833
834 scope = new_scope(cctx, FOR_SCOPE);
835 if (scope == NULL)
836 return NULL;
837
838 // Reserve a variable to store the loop iteration counter and initialize it
839 // to -1.
840 loop_lvar = reserve_local(cctx, (char_u *)"", 0, FALSE, &t_number);
841 if (loop_lvar == NULL)
842 {
843 // out of memory
844 drop_scope(cctx);
845 return NULL;
846 }
847 generate_STORENR(cctx, loop_lvar->lv_idx, -1);
848
849 // compile "expr", it remains on the stack until "endfor"
850 arg = p;
851 if (compile_expr0(&arg, cctx) == FAIL)
852 {
853 drop_scope(cctx);
854 return NULL;
855 }
856 arg_end = arg;
857
858 if (cctx->ctx_skip != SKIP_YES)
859 {
Dominique Pelleaf4a61a2021-12-27 17:21:41 +0000860 // If we know the type of "var" and it is not a supported type we can
Bram Moolenaardc7c3662021-12-20 15:04:29 +0000861 // give an error now.
Bram Moolenaar078a4612022-01-04 15:17:03 +0000862 vartype = get_type_on_stack(cctx, 0);
Bram Moolenaar59618fe2021-12-21 12:32:17 +0000863 if (vartype->tt_type != VAR_LIST
864 && vartype->tt_type != VAR_STRING
865 && vartype->tt_type != VAR_BLOB
866 && vartype->tt_type != VAR_ANY
867 && vartype->tt_type != VAR_UNKNOWN)
Bram Moolenaardc7c3662021-12-20 15:04:29 +0000868 {
869 semsg(_(e_for_loop_on_str_not_supported),
870 vartype_name(vartype->tt_type));
871 drop_scope(cctx);
872 return NULL;
873 }
874
875 if (vartype->tt_type == VAR_STRING)
876 item_type = &t_string;
877 else if (vartype->tt_type == VAR_BLOB)
878 item_type = &t_number;
879 else if (vartype->tt_type == VAR_LIST
880 && vartype->tt_member->tt_type != VAR_ANY)
881 {
882 if (!var_list)
883 item_type = vartype->tt_member;
884 else if (vartype->tt_member->tt_type == VAR_LIST
885 && vartype->tt_member->tt_member->tt_type != VAR_ANY)
886 item_type = vartype->tt_member->tt_member;
887 }
888
889 // CMDMOD_REV must come before the FOR instruction.
890 generate_undo_cmdmods(cctx);
891
892 // "for_end" is set when ":endfor" is found
893 scope->se_u.se_for.fs_top_label = current_instr_idx(cctx);
894
Bram Moolenaar2b4ecc22022-01-02 14:08:18 +0000895 if (cctx->ctx_compile_type == CT_DEBUG)
896 {
897 int save_prev_lnum = cctx->ctx_prev_lnum;
898 isn_T *isn;
899
900 // Add ISN_DEBUG here, before deciding to end the loop. There will
901 // be another ISN_DEBUG before the next instruction.
902 // Use the prev_lnum from the ISN_DEBUG instruction removed above.
903 // Increment the variable count so that the loop variable can be
904 // inspected.
905 cctx->ctx_prev_lnum = prev_lnum;
906 isn = generate_instr_debug(cctx);
907 ++isn->isn_arg.debug.dbg_var_names_len;
908 cctx->ctx_prev_lnum = save_prev_lnum;
909 }
910
Bram Moolenaardc7c3662021-12-20 15:04:29 +0000911 generate_FOR(cctx, loop_lvar->lv_idx);
912
913 arg = arg_start;
914 if (var_list)
915 {
916 generate_UNPACK(cctx, var_count, semicolon);
917 arg = skipwhite(arg + 1); // skip white after '['
918
Bram Moolenaar078a4612022-01-04 15:17:03 +0000919 // drop the list item
920 --cctx->ctx_type_stack.ga_len;
921
922 // add type of the items
Bram Moolenaardc7c3662021-12-20 15:04:29 +0000923 for (idx = 0; idx < var_count; ++idx)
924 {
Bram Moolenaar078a4612022-01-04 15:17:03 +0000925 type_T *type = (semicolon && idx == 0) ? vartype : item_type;
926
927 if (push_type_stack(cctx, type) == FAIL)
928 {
929 drop_scope(cctx);
930 return NULL;
931 }
Bram Moolenaardc7c3662021-12-20 15:04:29 +0000932 }
933 }
934
935 for (idx = 0; idx < var_count; ++idx)
936 {
937 assign_dest_T dest = dest_local;
938 int opt_flags = 0;
939 int vimvaridx = -1;
940 type_T *type = &t_any;
941 type_T *lhs_type = &t_any;
942 where_T where = WHERE_INIT;
943
944 p = skip_var_one(arg, FALSE);
945 varlen = p - arg;
946 name = vim_strnsave(arg, varlen);
947 if (name == NULL)
948 goto failed;
949 if (*p == ':')
950 {
951 p = skipwhite(p + 1);
952 lhs_type = parse_type(&p, cctx->ctx_type_list, TRUE);
953 }
954
955 if (get_var_dest(name, &dest, CMD_for, &opt_flags,
956 &vimvaridx, &type, cctx) == FAIL)
957 goto failed;
958 if (dest != dest_local)
959 {
960 if (generate_store_var(cctx, dest, opt_flags, vimvaridx,
961 0, 0, type, name) == FAIL)
962 goto failed;
963 }
964 else if (varlen == 1 && *arg == '_')
965 {
966 // Assigning to "_": drop the value.
967 if (generate_instr_drop(cctx, ISN_DROP, 1) == NULL)
968 goto failed;
969 }
970 else
971 {
972 // Script var is not supported.
973 if (STRNCMP(name, "s:", 2) == 0)
974 {
975 emsg(_(e_cannot_use_script_variable_in_for_loop));
976 goto failed;
977 }
978
979 if (!valid_varname(arg, (int)varlen, FALSE))
980 goto failed;
981 if (lookup_local(arg, varlen, NULL, cctx) == OK)
982 {
983 semsg(_(e_variable_already_declared), arg);
984 goto failed;
985 }
986
987 // Reserve a variable to store "var".
988 where.wt_index = var_list ? idx + 1 : 0;
989 where.wt_variable = TRUE;
990 if (lhs_type == &t_any)
991 lhs_type = item_type;
992 else if (item_type != &t_unknown
Bram Moolenaara1c51952022-02-02 16:20:26 +0000993 && need_type_where(item_type, lhs_type, -1,
994 where, cctx, FALSE, FALSE) == FAIL)
Bram Moolenaardc7c3662021-12-20 15:04:29 +0000995 goto failed;
996 var_lvar = reserve_local(cctx, arg, varlen, TRUE, lhs_type);
997 if (var_lvar == NULL)
998 // out of memory or used as an argument
999 goto failed;
1000
1001 if (semicolon && idx == var_count - 1)
1002 var_lvar->lv_type = vartype;
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001003 generate_STORE(cctx, ISN_STORE, var_lvar->lv_idx, NULL);
1004 }
1005
1006 if (*p == ',' || *p == ';')
1007 ++p;
1008 arg = skipwhite(p);
1009 vim_free(name);
1010 }
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001011 }
1012
1013 return arg_end;
1014
1015failed:
1016 vim_free(name);
1017 drop_scope(cctx);
1018 return NULL;
1019}
1020
1021/*
1022 * compile "endfor"
1023 */
1024 char_u *
1025compile_endfor(char_u *arg, cctx_T *cctx)
1026{
1027 garray_T *instr = &cctx->ctx_instr;
1028 scope_T *scope = cctx->ctx_scope;
1029 forscope_T *forscope;
1030 isn_T *isn;
1031
1032 if (misplaced_cmdmod(cctx))
1033 return NULL;
1034
1035 if (scope == NULL || scope->se_type != FOR_SCOPE)
1036 {
Bram Moolenaar436b5ad2021-12-31 22:49:24 +00001037 emsg(_(e_endfor_without_for));
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001038 return NULL;
1039 }
1040 forscope = &scope->se_u.se_for;
1041 cctx->ctx_scope = scope->se_outer;
1042 if (cctx->ctx_skip != SKIP_YES)
1043 {
1044 unwind_locals(cctx, scope->se_local_count);
1045
1046 // At end of ":for" scope jump back to the FOR instruction.
1047 generate_JUMP(cctx, JUMP_ALWAYS, forscope->fs_top_label);
1048
1049 // Fill in the "end" label in the FOR statement so it can jump here.
Bram Moolenaar2b4ecc22022-01-02 14:08:18 +00001050 // In debug mode an ISN_DEBUG was inserted.
1051 isn = ((isn_T *)instr->ga_data) + forscope->fs_top_label
1052 + (cctx->ctx_compile_type == CT_DEBUG ? 1 : 0);
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001053 isn->isn_arg.forloop.for_end = instr->ga_len;
1054
1055 // Fill in the "end" label any BREAK statements
1056 compile_fill_jump_to_end(&forscope->fs_end_label, instr->ga_len, cctx);
1057
1058 // Below the ":for" scope drop the "expr" list from the stack.
1059 if (generate_instr_drop(cctx, ISN_DROP, 1) == NULL)
1060 return NULL;
1061 }
1062
1063 vim_free(scope);
1064
1065 return arg;
1066}
1067
1068/*
1069 * compile "while expr"
1070 *
1071 * Produces instructions:
1072 * top: EVAL expr Push result of "expr"
1073 * JUMP_IF_FALSE end jump if false
1074 * ... body ...
1075 * JUMP top Jump back to repeat
1076 * end:
1077 *
1078 */
1079 char_u *
1080compile_while(char_u *arg, cctx_T *cctx)
1081{
1082 char_u *p = arg;
1083 scope_T *scope;
1084
1085 scope = new_scope(cctx, WHILE_SCOPE);
1086 if (scope == NULL)
1087 return NULL;
1088
1089 // "endwhile" jumps back here, one before when profiling or using cmdmods
1090 scope->se_u.se_while.ws_top_label = current_instr_idx(cctx);
1091
1092 // compile "expr"
1093 if (compile_expr0(&p, cctx) == FAIL)
1094 return NULL;
1095
1096 if (!ends_excmd2(arg, skipwhite(p)))
1097 {
Bram Moolenaar74409f62022-01-01 15:58:22 +00001098 semsg(_(e_trailing_characters_str), p);
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001099 return NULL;
1100 }
1101
1102 if (cctx->ctx_skip != SKIP_YES)
1103 {
1104 if (bool_on_stack(cctx) == FAIL)
1105 return FAIL;
1106
1107 // CMDMOD_REV must come before the jump
1108 generate_undo_cmdmods(cctx);
1109
1110 // "while_end" is set when ":endwhile" is found
1111 if (compile_jump_to_end(&scope->se_u.se_while.ws_end_label,
1112 JUMP_IF_FALSE, cctx) == FAIL)
1113 return FAIL;
1114 }
1115
1116 return p;
1117}
1118
1119/*
1120 * compile "endwhile"
1121 */
1122 char_u *
1123compile_endwhile(char_u *arg, cctx_T *cctx)
1124{
1125 scope_T *scope = cctx->ctx_scope;
1126 garray_T *instr = &cctx->ctx_instr;
1127
1128 if (misplaced_cmdmod(cctx))
1129 return NULL;
1130 if (scope == NULL || scope->se_type != WHILE_SCOPE)
1131 {
Bram Moolenaar436b5ad2021-12-31 22:49:24 +00001132 emsg(_(e_endwhile_without_while));
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001133 return NULL;
1134 }
1135 cctx->ctx_scope = scope->se_outer;
1136 if (cctx->ctx_skip != SKIP_YES)
1137 {
1138 unwind_locals(cctx, scope->se_local_count);
1139
1140#ifdef FEAT_PROFILE
1141 // count the endwhile before jumping
1142 may_generate_prof_end(cctx, cctx->ctx_lnum);
1143#endif
1144
1145 // At end of ":for" scope jump back to the FOR instruction.
1146 generate_JUMP(cctx, JUMP_ALWAYS, scope->se_u.se_while.ws_top_label);
1147
1148 // Fill in the "end" label in the WHILE statement so it can jump here.
1149 // And in any jumps for ":break"
1150 compile_fill_jump_to_end(&scope->se_u.se_while.ws_end_label,
1151 instr->ga_len, cctx);
1152 }
1153
1154 vim_free(scope);
1155
1156 return arg;
1157}
1158
1159/*
1160 * compile "continue"
1161 */
1162 char_u *
1163compile_continue(char_u *arg, cctx_T *cctx)
1164{
1165 scope_T *scope = cctx->ctx_scope;
1166 int try_scopes = 0;
1167 int loop_label;
1168
1169 for (;;)
1170 {
1171 if (scope == NULL)
1172 {
Bram Moolenaar3a846e62022-01-01 16:21:00 +00001173 emsg(_(e_continue_without_while_or_for));
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001174 return NULL;
1175 }
1176 if (scope->se_type == FOR_SCOPE)
1177 {
1178 loop_label = scope->se_u.se_for.fs_top_label;
1179 break;
1180 }
1181 if (scope->se_type == WHILE_SCOPE)
1182 {
1183 loop_label = scope->se_u.se_while.ws_top_label;
1184 break;
1185 }
1186 if (scope->se_type == TRY_SCOPE)
1187 ++try_scopes;
1188 scope = scope->se_outer;
1189 }
1190
1191 if (try_scopes > 0)
1192 // Inside one or more try/catch blocks we first need to jump to the
1193 // "finally" or "endtry" to cleanup.
1194 generate_TRYCONT(cctx, try_scopes, loop_label);
1195 else
1196 // Jump back to the FOR or WHILE instruction.
1197 generate_JUMP(cctx, JUMP_ALWAYS, loop_label);
1198
1199 return arg;
1200}
1201
1202/*
1203 * compile "break"
1204 */
1205 char_u *
1206compile_break(char_u *arg, cctx_T *cctx)
1207{
1208 scope_T *scope = cctx->ctx_scope;
Bram Moolenaar873f8242022-03-10 21:53:44 +00001209 int try_scopes = 0;
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001210 endlabel_T **el;
1211
1212 for (;;)
1213 {
1214 if (scope == NULL)
1215 {
Bram Moolenaar3a846e62022-01-01 16:21:00 +00001216 emsg(_(e_break_without_while_or_for));
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001217 return NULL;
1218 }
Bram Moolenaar873f8242022-03-10 21:53:44 +00001219 if (scope->se_type == FOR_SCOPE)
1220 {
1221 el = &scope->se_u.se_for.fs_end_label;
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001222 break;
Bram Moolenaar873f8242022-03-10 21:53:44 +00001223 }
1224 if (scope->se_type == WHILE_SCOPE)
1225 {
1226 el = &scope->se_u.se_while.ws_end_label;
1227 break;
1228 }
1229 if (scope->se_type == TRY_SCOPE)
1230 ++try_scopes;
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001231 scope = scope->se_outer;
1232 }
1233
Bram Moolenaar873f8242022-03-10 21:53:44 +00001234 if (try_scopes > 0)
1235 // Inside one or more try/catch blocks we first need to jump to the
1236 // "finally" or "endtry" to cleanup. Then come to the next JUMP
1237 // intruction, which we don't know the index of yet.
1238 generate_TRYCONT(cctx, try_scopes, cctx->ctx_instr.ga_len + 1);
1239
1240 // Jump to the end of the FOR or WHILE loop. The instruction index will be
1241 // filled in later.
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001242 if (compile_jump_to_end(el, JUMP_ALWAYS, cctx) == FAIL)
1243 return FAIL;
1244
1245 return arg;
1246}
1247
1248/*
1249 * compile "{" start of block
1250 */
1251 char_u *
1252compile_block(char_u *arg, cctx_T *cctx)
1253{
1254 if (new_scope(cctx, BLOCK_SCOPE) == NULL)
1255 return NULL;
1256 return skipwhite(arg + 1);
1257}
1258
1259/*
1260 * compile end of block: drop one scope
1261 */
1262 void
1263compile_endblock(cctx_T *cctx)
1264{
1265 scope_T *scope = cctx->ctx_scope;
1266
1267 cctx->ctx_scope = scope->se_outer;
1268 unwind_locals(cctx, scope->se_local_count);
1269 vim_free(scope);
1270}
1271
1272/*
1273 * Compile "try".
1274 * Creates a new scope for the try-endtry, pointing to the first catch and
1275 * finally.
1276 * Creates another scope for the "try" block itself.
1277 * TRY instruction sets up exception handling at runtime.
1278 *
1279 * "try"
1280 * TRY -> catch1, -> finally push trystack entry
1281 * ... try block
1282 * "throw {exception}"
1283 * EVAL {exception}
1284 * THROW create exception
1285 * ... try block
1286 * " catch {expr}"
1287 * JUMP -> finally
1288 * catch1: PUSH exception
1289 * EVAL {expr}
1290 * MATCH
1291 * JUMP nomatch -> catch2
1292 * CATCH remove exception
1293 * ... catch block
1294 * " catch"
1295 * JUMP -> finally
1296 * catch2: CATCH remove exception
1297 * ... catch block
1298 * " finally"
1299 * finally:
1300 * ... finally block
1301 * " endtry"
1302 * ENDTRY pop trystack entry, may rethrow
1303 */
1304 char_u *
1305compile_try(char_u *arg, cctx_T *cctx)
1306{
1307 garray_T *instr = &cctx->ctx_instr;
1308 scope_T *try_scope;
1309 scope_T *scope;
1310
1311 if (misplaced_cmdmod(cctx))
1312 return NULL;
1313
1314 // scope that holds the jumps that go to catch/finally/endtry
1315 try_scope = new_scope(cctx, TRY_SCOPE);
1316 if (try_scope == NULL)
1317 return NULL;
1318
1319 if (cctx->ctx_skip != SKIP_YES)
1320 {
1321 isn_T *isn;
1322
1323 // "try_catch" is set when the first ":catch" is found or when no catch
1324 // is found and ":finally" is found.
1325 // "try_finally" is set when ":finally" is found
1326 // "try_endtry" is set when ":endtry" is found
1327 try_scope->se_u.se_try.ts_try_label = instr->ga_len;
1328 if ((isn = generate_instr(cctx, ISN_TRY)) == NULL)
1329 return NULL;
Bram Moolenaar0d807102021-12-21 09:42:09 +00001330 isn->isn_arg.tryref.try_ref = ALLOC_CLEAR_ONE(tryref_T);
1331 if (isn->isn_arg.tryref.try_ref == NULL)
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001332 return NULL;
1333 }
1334
1335 // scope for the try block itself
1336 scope = new_scope(cctx, BLOCK_SCOPE);
1337 if (scope == NULL)
1338 return NULL;
1339
1340 return arg;
1341}
1342
1343/*
1344 * Compile "catch {expr}".
1345 */
1346 char_u *
1347compile_catch(char_u *arg, cctx_T *cctx UNUSED)
1348{
1349 scope_T *scope = cctx->ctx_scope;
1350 garray_T *instr = &cctx->ctx_instr;
1351 char_u *p;
1352 isn_T *isn;
1353
1354 if (misplaced_cmdmod(cctx))
1355 return NULL;
1356
1357 // end block scope from :try or :catch
1358 if (scope != NULL && scope->se_type == BLOCK_SCOPE)
1359 compile_endblock(cctx);
1360 scope = cctx->ctx_scope;
1361
1362 // Error if not in a :try scope
1363 if (scope == NULL || scope->se_type != TRY_SCOPE)
1364 {
Bram Moolenaar436b5ad2021-12-31 22:49:24 +00001365 emsg(_(e_catch_without_try));
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001366 return NULL;
1367 }
1368
1369 if (scope->se_u.se_try.ts_caught_all)
1370 {
1371 emsg(_(e_catch_unreachable_after_catch_all));
1372 return NULL;
1373 }
Bram Moolenaar53c29612022-01-12 16:18:18 +00001374 if (!cctx->ctx_had_return)
1375 scope->se_u.se_try.ts_no_return = TRUE;
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001376
1377 if (cctx->ctx_skip != SKIP_YES)
1378 {
1379#ifdef FEAT_PROFILE
1380 // the profile-start should be after the jump
1381 if (cctx->ctx_compile_type == CT_PROFILE
1382 && instr->ga_len > 0
1383 && ((isn_T *)instr->ga_data)[instr->ga_len - 1]
1384 .isn_type == ISN_PROF_START)
1385 --instr->ga_len;
1386#endif
1387 // Jump from end of previous block to :finally or :endtry
1388 if (compile_jump_to_end(&scope->se_u.se_try.ts_end_label,
1389 JUMP_ALWAYS, cctx) == FAIL)
1390 return NULL;
1391
1392 // End :try or :catch scope: set value in ISN_TRY instruction
1393 isn = ((isn_T *)instr->ga_data) + scope->se_u.se_try.ts_try_label;
Bram Moolenaar0d807102021-12-21 09:42:09 +00001394 if (isn->isn_arg.tryref.try_ref->try_catch == 0)
1395 isn->isn_arg.tryref.try_ref->try_catch = instr->ga_len;
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001396 if (scope->se_u.se_try.ts_catch_label != 0)
1397 {
1398 // Previous catch without match jumps here
1399 isn = ((isn_T *)instr->ga_data) + scope->se_u.se_try.ts_catch_label;
1400 isn->isn_arg.jump.jump_where = instr->ga_len;
1401 }
1402#ifdef FEAT_PROFILE
1403 if (cctx->ctx_compile_type == CT_PROFILE)
1404 {
1405 // a "throw" that jumps here needs to be counted
1406 generate_instr(cctx, ISN_PROF_END);
1407 // the "catch" is also counted
1408 generate_instr(cctx, ISN_PROF_START);
1409 }
1410#endif
1411 if (cctx->ctx_compile_type == CT_DEBUG)
1412 generate_instr_debug(cctx);
1413 }
1414
1415 p = skipwhite(arg);
1416 if (ends_excmd2(arg, p))
1417 {
1418 scope->se_u.se_try.ts_caught_all = TRUE;
1419 scope->se_u.se_try.ts_catch_label = 0;
1420 }
1421 else
1422 {
1423 char_u *end;
1424 char_u *pat;
1425 char_u *tofree = NULL;
1426 int dropped = 0;
1427 int len;
1428
1429 // Push v:exception, push {expr} and MATCH
1430 generate_instr_type(cctx, ISN_PUSHEXC, &t_string);
1431
1432 end = skip_regexp_ex(p + 1, *p, TRUE, &tofree, &dropped, NULL);
1433 if (*end != *p)
1434 {
1435 semsg(_(e_separator_mismatch_str), p);
1436 vim_free(tofree);
Bram Moolenaar54969f42022-02-07 13:56:44 +00001437 return NULL;
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001438 }
1439 if (tofree == NULL)
1440 len = (int)(end - (p + 1));
1441 else
1442 len = (int)(end - tofree);
1443 pat = vim_strnsave(tofree == NULL ? p + 1 : tofree, len);
1444 vim_free(tofree);
1445 p += len + 2 + dropped;
1446 if (pat == NULL)
Bram Moolenaar54969f42022-02-07 13:56:44 +00001447 return NULL;
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001448 if (generate_PUSHS(cctx, &pat) == FAIL)
Bram Moolenaar54969f42022-02-07 13:56:44 +00001449 return NULL;
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001450
1451 if (generate_COMPARE(cctx, EXPR_MATCH, FALSE) == FAIL)
1452 return NULL;
1453
1454 scope->se_u.se_try.ts_catch_label = instr->ga_len;
1455 if (generate_JUMP(cctx, JUMP_IF_FALSE, 0) == FAIL)
1456 return NULL;
1457 }
1458
1459 if (cctx->ctx_skip != SKIP_YES && generate_instr(cctx, ISN_CATCH) == NULL)
1460 return NULL;
1461
1462 if (new_scope(cctx, BLOCK_SCOPE) == NULL)
1463 return NULL;
1464 return p;
1465}
1466
1467 char_u *
1468compile_finally(char_u *arg, cctx_T *cctx)
1469{
1470 scope_T *scope = cctx->ctx_scope;
1471 garray_T *instr = &cctx->ctx_instr;
1472 isn_T *isn;
1473 int this_instr;
1474
1475 if (misplaced_cmdmod(cctx))
1476 return NULL;
1477
1478 // end block scope from :try or :catch
1479 if (scope != NULL && scope->se_type == BLOCK_SCOPE)
1480 compile_endblock(cctx);
1481 scope = cctx->ctx_scope;
1482
1483 // Error if not in a :try scope
1484 if (scope == NULL || scope->se_type != TRY_SCOPE)
1485 {
Bram Moolenaar436b5ad2021-12-31 22:49:24 +00001486 emsg(_(e_finally_without_try));
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001487 return NULL;
1488 }
1489
1490 if (cctx->ctx_skip != SKIP_YES)
1491 {
1492 // End :catch or :finally scope: set value in ISN_TRY instruction
1493 isn = ((isn_T *)instr->ga_data) + scope->se_u.se_try.ts_try_label;
Bram Moolenaar0d807102021-12-21 09:42:09 +00001494 if (isn->isn_arg.tryref.try_ref->try_finally != 0)
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001495 {
Bram Moolenaar436b5ad2021-12-31 22:49:24 +00001496 emsg(_(e_multiple_finally));
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001497 return NULL;
1498 }
1499
1500 this_instr = instr->ga_len;
1501#ifdef FEAT_PROFILE
1502 if (cctx->ctx_compile_type == CT_PROFILE
1503 && ((isn_T *)instr->ga_data)[this_instr - 1]
1504 .isn_type == ISN_PROF_START)
1505 {
1506 // jump to the profile start of the "finally"
1507 --this_instr;
1508
1509 // jump to the profile end above it
1510 if (this_instr > 0 && ((isn_T *)instr->ga_data)[this_instr - 1]
1511 .isn_type == ISN_PROF_END)
1512 --this_instr;
1513 }
1514#endif
1515
1516 // Fill in the "end" label in jumps at the end of the blocks.
1517 compile_fill_jump_to_end(&scope->se_u.se_try.ts_end_label,
1518 this_instr, cctx);
1519
1520 // If there is no :catch then an exception jumps to :finally.
Bram Moolenaar0d807102021-12-21 09:42:09 +00001521 if (isn->isn_arg.tryref.try_ref->try_catch == 0)
1522 isn->isn_arg.tryref.try_ref->try_catch = this_instr;
1523 isn->isn_arg.tryref.try_ref->try_finally = this_instr;
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001524 if (scope->se_u.se_try.ts_catch_label != 0)
1525 {
1526 // Previous catch without match jumps here
1527 isn = ((isn_T *)instr->ga_data) + scope->se_u.se_try.ts_catch_label;
1528 isn->isn_arg.jump.jump_where = this_instr;
1529 scope->se_u.se_try.ts_catch_label = 0;
1530 }
Bram Moolenaar53c29612022-01-12 16:18:18 +00001531 scope->se_u.se_try.ts_has_finally = TRUE;
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001532 if (generate_instr(cctx, ISN_FINALLY) == NULL)
1533 return NULL;
1534 }
1535
1536 return arg;
1537}
1538
1539 char_u *
1540compile_endtry(char_u *arg, cctx_T *cctx)
1541{
1542 scope_T *scope = cctx->ctx_scope;
1543 garray_T *instr = &cctx->ctx_instr;
1544 isn_T *try_isn;
1545
1546 if (misplaced_cmdmod(cctx))
1547 return NULL;
1548
1549 // end block scope from :catch or :finally
1550 if (scope != NULL && scope->se_type == BLOCK_SCOPE)
1551 compile_endblock(cctx);
1552 scope = cctx->ctx_scope;
1553
1554 // Error if not in a :try scope
1555 if (scope == NULL || scope->se_type != TRY_SCOPE)
1556 {
1557 if (scope == NULL)
Bram Moolenaar436b5ad2021-12-31 22:49:24 +00001558 emsg(_(e_endtry_without_try));
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001559 else if (scope->se_type == WHILE_SCOPE)
Bram Moolenaar1a992222021-12-31 17:25:48 +00001560 emsg(_(e_missing_endwhile));
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001561 else if (scope->se_type == FOR_SCOPE)
Bram Moolenaar1a992222021-12-31 17:25:48 +00001562 emsg(_(e_missing_endfor));
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001563 else
Bram Moolenaar1a992222021-12-31 17:25:48 +00001564 emsg(_(e_missing_endif));
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001565 return NULL;
1566 }
1567
1568 try_isn = ((isn_T *)instr->ga_data) + scope->se_u.se_try.ts_try_label;
1569 if (cctx->ctx_skip != SKIP_YES)
1570 {
Bram Moolenaar0d807102021-12-21 09:42:09 +00001571 if (try_isn->isn_arg.tryref.try_ref->try_catch == 0
1572 && try_isn->isn_arg.tryref.try_ref->try_finally == 0)
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001573 {
1574 emsg(_(e_missing_catch_or_finally));
1575 return NULL;
1576 }
1577
1578#ifdef FEAT_PROFILE
1579 if (cctx->ctx_compile_type == CT_PROFILE
1580 && ((isn_T *)instr->ga_data)[instr->ga_len - 1]
1581 .isn_type == ISN_PROF_START)
1582 // move the profile start after "endtry" so that it's not counted when
1583 // the exception is rethrown.
1584 --instr->ga_len;
1585#endif
1586
1587 // Fill in the "end" label in jumps at the end of the blocks, if not
1588 // done by ":finally".
1589 compile_fill_jump_to_end(&scope->se_u.se_try.ts_end_label,
1590 instr->ga_len, cctx);
1591
1592 if (scope->se_u.se_try.ts_catch_label != 0)
1593 {
1594 // Last catch without match jumps here
1595 isn_T *isn = ((isn_T *)instr->ga_data)
1596 + scope->se_u.se_try.ts_catch_label;
1597 isn->isn_arg.jump.jump_where = instr->ga_len;
1598 }
1599 }
1600
Bram Moolenaar53c29612022-01-12 16:18:18 +00001601 // If there is a finally clause that ends in return then we will return.
1602 // If one of the blocks didn't end in "return" or we did not catch all
1603 // exceptions reset the had_return flag.
1604 if (!(scope->se_u.se_try.ts_has_finally && cctx->ctx_had_return)
1605 && (scope->se_u.se_try.ts_no_return
1606 || !scope->se_u.se_try.ts_caught_all))
1607 cctx->ctx_had_return = FALSE;
1608
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001609 compile_endblock(cctx);
1610
1611 if (cctx->ctx_skip != SKIP_YES)
1612 {
1613 // End :catch or :finally scope: set instruction index in ISN_TRY
1614 // instruction
Bram Moolenaar0d807102021-12-21 09:42:09 +00001615 try_isn->isn_arg.tryref.try_ref->try_endtry = instr->ga_len;
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001616 if (cctx->ctx_skip != SKIP_YES
1617 && generate_instr(cctx, ISN_ENDTRY) == NULL)
1618 return NULL;
1619#ifdef FEAT_PROFILE
1620 if (cctx->ctx_compile_type == CT_PROFILE)
1621 generate_instr(cctx, ISN_PROF_START);
1622#endif
1623 }
1624 return arg;
1625}
1626
1627/*
1628 * compile "throw {expr}"
1629 */
1630 char_u *
1631compile_throw(char_u *arg, cctx_T *cctx UNUSED)
1632{
1633 char_u *p = skipwhite(arg);
1634
1635 if (compile_expr0(&p, cctx) == FAIL)
1636 return NULL;
1637 if (cctx->ctx_skip == SKIP_YES)
1638 return p;
1639 if (may_generate_2STRING(-1, FALSE, cctx) == FAIL)
1640 return NULL;
1641 if (generate_instr_drop(cctx, ISN_THROW, 1) == NULL)
1642 return NULL;
1643
1644 return p;
1645}
1646
1647 char_u *
1648compile_eval(char_u *arg, cctx_T *cctx)
1649{
1650 char_u *p = arg;
1651 int name_only;
1652 long lnum = SOURCING_LNUM;
1653
1654 // find_ex_command() will consider a variable name an expression, assuming
1655 // that something follows on the next line. Check that something actually
1656 // follows, otherwise it's probably a misplaced command.
1657 name_only = cmd_is_name_only(arg);
1658
1659 if (compile_expr0(&p, cctx) == FAIL)
1660 return NULL;
1661
1662 if (name_only && lnum == SOURCING_LNUM)
1663 {
1664 semsg(_(e_expression_without_effect_str), arg);
1665 return NULL;
1666 }
1667
1668 // drop the result
1669 generate_instr_drop(cctx, ISN_DROP, 1);
1670
1671 return skipwhite(p);
1672}
1673
1674/*
1675 * compile "echo expr"
1676 * compile "echomsg expr"
1677 * compile "echoerr expr"
1678 * compile "echoconsole expr"
1679 * compile "execute expr"
1680 */
1681 char_u *
1682compile_mult_expr(char_u *arg, int cmdidx, cctx_T *cctx)
1683{
1684 char_u *p = arg;
1685 char_u *prev = arg;
1686 char_u *expr_start;
1687 int count = 0;
1688 int start_ctx_lnum = cctx->ctx_lnum;
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001689 type_T *type;
1690
1691 for (;;)
1692 {
1693 if (ends_excmd2(prev, p))
1694 break;
1695 expr_start = p;
1696 if (compile_expr0(&p, cctx) == FAIL)
1697 return NULL;
1698
1699 if (cctx->ctx_skip != SKIP_YES)
1700 {
1701 // check for non-void type
Bram Moolenaar078a4612022-01-04 15:17:03 +00001702 type = get_type_on_stack(cctx, 0);
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001703 if (type->tt_type == VAR_VOID)
1704 {
1705 semsg(_(e_expression_does_not_result_in_value_str), expr_start);
1706 return NULL;
1707 }
1708 }
1709
1710 ++count;
1711 prev = p;
1712 p = skipwhite(p);
1713 }
1714
1715 if (count > 0)
1716 {
1717 long save_lnum = cctx->ctx_lnum;
1718
1719 // Use the line number where the command started.
1720 cctx->ctx_lnum = start_ctx_lnum;
1721
1722 if (cmdidx == CMD_echo || cmdidx == CMD_echon)
1723 generate_ECHO(cctx, cmdidx == CMD_echo, count);
1724 else if (cmdidx == CMD_execute)
1725 generate_MULT_EXPR(cctx, ISN_EXECUTE, count);
1726 else if (cmdidx == CMD_echomsg)
1727 generate_MULT_EXPR(cctx, ISN_ECHOMSG, count);
1728 else if (cmdidx == CMD_echoconsole)
1729 generate_MULT_EXPR(cctx, ISN_ECHOCONSOLE, count);
1730 else
1731 generate_MULT_EXPR(cctx, ISN_ECHOERR, count);
1732
1733 cctx->ctx_lnum = save_lnum;
1734 }
1735 return p;
1736}
1737
1738/*
1739 * If "eap" has a range that is not a constant generate an ISN_RANGE
1740 * instruction to compute it and return OK.
1741 * Otherwise return FAIL, the caller must deal with any range.
1742 */
1743 static int
1744compile_variable_range(exarg_T *eap, cctx_T *cctx)
1745{
1746 char_u *range_end = skip_range(eap->cmd, TRUE, NULL);
1747 char_u *p = skipdigits(eap->cmd);
1748
1749 if (p == range_end)
1750 return FAIL;
1751 return generate_RANGE(cctx, vim_strnsave(eap->cmd, range_end - eap->cmd));
1752}
1753
1754/*
1755 * :put r
1756 * :put ={expr}
1757 */
1758 char_u *
1759compile_put(char_u *arg, exarg_T *eap, cctx_T *cctx)
1760{
1761 char_u *line = arg;
1762 linenr_T lnum;
1763 char *errormsg;
1764 int above = eap->forceit;
1765
1766 eap->regname = *line;
1767
1768 if (eap->regname == '=')
1769 {
Bram Moolenaard0b7bfa2022-03-12 14:51:16 +00001770 char_u *p = skipwhite(line + 1);
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001771
1772 if (compile_expr0(&p, cctx) == FAIL)
1773 return NULL;
1774 line = p;
1775 }
1776 else if (eap->regname != NUL)
1777 ++line;
1778
1779 if (compile_variable_range(eap, cctx) == OK)
1780 {
1781 lnum = above ? LNUM_VARIABLE_RANGE_ABOVE : LNUM_VARIABLE_RANGE;
1782 }
1783 else
1784 {
1785 // Either no range or a number.
1786 // "errormsg" will not be set because the range is ADDR_LINES.
1787 if (parse_cmd_address(eap, &errormsg, FALSE) == FAIL)
1788 // cannot happen
1789 return NULL;
1790 if (eap->addr_count == 0)
1791 lnum = -1;
1792 else
1793 lnum = eap->line2;
1794 if (above)
1795 --lnum;
1796 }
1797
1798 generate_PUT(cctx, eap->regname, lnum);
1799 return line;
1800}
1801
1802/*
1803 * A command that is not compiled, execute with legacy code.
1804 */
1805 char_u *
1806compile_exec(char_u *line_arg, exarg_T *eap, cctx_T *cctx)
1807{
1808 char_u *line = line_arg;
1809 char_u *p;
1810 int has_expr = FALSE;
1811 char_u *nextcmd = (char_u *)"";
1812 char_u *tofree = NULL;
1813 char_u *cmd_arg = NULL;
1814
1815 if (cctx->ctx_skip == SKIP_YES)
1816 goto theend;
1817
1818 // If there was a prececing command modifier, drop it and include it in the
1819 // EXEC command.
1820 if (cctx->ctx_has_cmdmod)
1821 {
1822 garray_T *instr = &cctx->ctx_instr;
1823 isn_T *isn = ((isn_T *)instr->ga_data) + instr->ga_len - 1;
1824
1825 if (isn->isn_type == ISN_CMDMOD)
1826 {
1827 vim_regfree(isn->isn_arg.cmdmod.cf_cmdmod
1828 ->cmod_filter_regmatch.regprog);
1829 vim_free(isn->isn_arg.cmdmod.cf_cmdmod);
1830 --instr->ga_len;
1831 cctx->ctx_has_cmdmod = FALSE;
1832 }
1833 }
1834
1835 if (eap->cmdidx >= 0 && eap->cmdidx < CMD_SIZE)
1836 {
1837 long argt = eap->argt;
1838 int usefilter = FALSE;
1839
1840 has_expr = argt & (EX_XFILE | EX_EXPAND);
1841
1842 // If the command can be followed by a bar, find the bar and truncate
1843 // it, so that the following command can be compiled.
1844 // The '|' is overwritten with a NUL, it is put back below.
1845 if ((eap->cmdidx == CMD_write || eap->cmdidx == CMD_read)
1846 && *eap->arg == '!')
1847 // :w !filter or :r !filter or :r! filter
1848 usefilter = TRUE;
1849 if ((argt & EX_TRLBAR) && !usefilter)
1850 {
1851 eap->argt = argt;
1852 separate_nextcmd(eap);
1853 if (eap->nextcmd != NULL)
1854 nextcmd = eap->nextcmd;
1855 }
1856 else if (eap->cmdidx == CMD_wincmd)
1857 {
1858 p = eap->arg;
1859 if (*p != NUL)
1860 ++p;
1861 if (*p == 'g' || *p == Ctrl_G)
1862 ++p;
1863 p = skipwhite(p);
1864 if (*p == '|')
1865 {
1866 *p = NUL;
1867 nextcmd = p + 1;
1868 }
1869 }
1870 else if (eap->cmdidx == CMD_command || eap->cmdidx == CMD_autocmd)
1871 {
1872 // If there is a trailing '{' read lines until the '}'
1873 p = eap->arg + STRLEN(eap->arg) - 1;
1874 while (p > eap->arg && VIM_ISWHITE(*p))
1875 --p;
1876 if (*p == '{')
1877 {
1878 exarg_T ea;
Bram Moolenaar62628d92022-02-25 21:10:53 +00001879 int flags = 0; // unused
Bram Moolenaardc7c3662021-12-20 15:04:29 +00001880 int start_lnum = SOURCING_LNUM;
1881
1882 CLEAR_FIELD(ea);
1883 ea.arg = eap->arg;
1884 fill_exarg_from_cctx(&ea, cctx);
1885 (void)may_get_cmd_block(&ea, p, &tofree, &flags);
1886 if (tofree != NULL)
1887 {
1888 *p = NUL;
1889 line = concat_str(line, tofree);
1890 if (line == NULL)
1891 goto theend;
1892 vim_free(tofree);
1893 tofree = line;
1894 SOURCING_LNUM = start_lnum;
1895 }
1896 }
1897 }
1898 }
1899
1900 if (eap->cmdidx == CMD_syntax && STRNCMP(eap->arg, "include ", 8) == 0)
1901 {
1902 // expand filename in "syntax include [@group] filename"
1903 has_expr = TRUE;
1904 eap->arg = skipwhite(eap->arg + 7);
1905 if (*eap->arg == '@')
1906 eap->arg = skiptowhite(eap->arg);
1907 }
1908
1909 if ((eap->cmdidx == CMD_global || eap->cmdidx == CMD_vglobal)
1910 && STRLEN(eap->arg) > 4)
1911 {
1912 int delim = *eap->arg;
1913
1914 p = skip_regexp_ex(eap->arg + 1, delim, TRUE, NULL, NULL, NULL);
1915 if (*p == delim)
1916 cmd_arg = p + 1;
1917 }
1918
1919 if (eap->cmdidx == CMD_folddoopen || eap->cmdidx == CMD_folddoclosed)
1920 cmd_arg = eap->arg;
1921
1922 if (cmd_arg != NULL)
1923 {
1924 exarg_T nea;
1925
1926 CLEAR_FIELD(nea);
1927 nea.cmd = cmd_arg;
1928 p = find_ex_command(&nea, NULL, lookup_scriptitem, NULL);
1929 if (nea.cmdidx < CMD_SIZE)
1930 {
1931 has_expr = excmd_get_argt(nea.cmdidx) & (EX_XFILE | EX_EXPAND);
1932 if (has_expr)
1933 eap->arg = skiptowhite(eap->arg);
1934 }
1935 }
1936
1937 if (has_expr && (p = (char_u *)strstr((char *)eap->arg, "`=")) != NULL)
1938 {
1939 int count = 0;
1940 char_u *start = skipwhite(line);
1941
1942 // :cmd xxx`=expr1`yyy`=expr2`zzz
1943 // PUSHS ":cmd xxx"
1944 // eval expr1
1945 // PUSHS "yyy"
1946 // eval expr2
1947 // PUSHS "zzz"
1948 // EXECCONCAT 5
1949 for (;;)
1950 {
1951 if (p > start)
1952 {
1953 char_u *val = vim_strnsave(start, p - start);
1954
1955 generate_PUSHS(cctx, &val);
1956 ++count;
1957 }
1958 p += 2;
1959 if (compile_expr0(&p, cctx) == FAIL)
1960 return NULL;
1961 may_generate_2STRING(-1, TRUE, cctx);
1962 ++count;
1963 p = skipwhite(p);
1964 if (*p != '`')
1965 {
1966 emsg(_(e_missing_backtick));
1967 return NULL;
1968 }
1969 start = p + 1;
1970
1971 p = (char_u *)strstr((char *)start, "`=");
1972 if (p == NULL)
1973 {
1974 if (*skipwhite(start) != NUL)
1975 {
1976 char_u *val = vim_strsave(start);
1977
1978 generate_PUSHS(cctx, &val);
1979 ++count;
1980 }
1981 break;
1982 }
1983 }
1984 generate_EXECCONCAT(cctx, count);
1985 }
1986 else
1987 generate_EXEC_copy(cctx, ISN_EXEC, line);
1988
1989theend:
1990 if (*nextcmd != NUL)
1991 {
1992 // the parser expects a pointer to the bar, put it back
1993 --nextcmd;
1994 *nextcmd = '|';
1995 }
1996 vim_free(tofree);
1997
1998 return nextcmd;
1999}
2000
2001/*
2002 * A script command with heredoc, e.g.
2003 * ruby << EOF
2004 * command
2005 * EOF
2006 * Has been turned into one long line with NL characters by
2007 * get_function_body():
2008 * ruby << EOF<NL> command<NL>EOF
2009 */
2010 char_u *
2011compile_script(char_u *line, cctx_T *cctx)
2012{
2013 if (cctx->ctx_skip != SKIP_YES)
2014 {
2015 isn_T *isn;
2016
2017 if ((isn = generate_instr(cctx, ISN_EXEC_SPLIT)) == NULL)
2018 return NULL;
2019 isn->isn_arg.string = vim_strsave(line);
2020 }
2021 return (char_u *)"";
2022}
2023
2024
2025/*
2026 * :s/pat/repl/
2027 */
2028 char_u *
2029compile_substitute(char_u *arg, exarg_T *eap, cctx_T *cctx)
2030{
2031 char_u *cmd = eap->arg;
2032 char_u *expr = (char_u *)strstr((char *)cmd, "\\=");
2033
2034 if (expr != NULL)
2035 {
2036 int delimiter = *cmd++;
2037
2038 // There is a \=expr, find it in the substitute part.
2039 cmd = skip_regexp_ex(cmd, delimiter, magic_isset(), NULL, NULL, NULL);
2040 if (cmd[0] == delimiter && cmd[1] == '\\' && cmd[2] == '=')
2041 {
2042 garray_T save_ga = cctx->ctx_instr;
2043 char_u *end;
2044 int expr_res;
2045 int trailing_error;
2046 int instr_count;
2047 isn_T *instr;
2048 isn_T *isn;
2049
2050 cmd += 3;
2051 end = skip_substitute(cmd, delimiter);
2052
2053 // Temporarily reset the list of instructions so that the jump
2054 // labels are correct.
2055 cctx->ctx_instr.ga_len = 0;
2056 cctx->ctx_instr.ga_maxlen = 0;
2057 cctx->ctx_instr.ga_data = NULL;
2058 expr_res = compile_expr0(&cmd, cctx);
2059 if (end[-1] == NUL)
2060 end[-1] = delimiter;
2061 cmd = skipwhite(cmd);
2062 trailing_error = *cmd != delimiter && *cmd != NUL;
2063
2064 if (expr_res == FAIL || trailing_error
2065 || GA_GROW_FAILS(&cctx->ctx_instr, 1))
2066 {
2067 if (trailing_error)
Bram Moolenaar74409f62022-01-01 15:58:22 +00002068 semsg(_(e_trailing_characters_str), cmd);
Bram Moolenaardc7c3662021-12-20 15:04:29 +00002069 clear_instr_ga(&cctx->ctx_instr);
2070 cctx->ctx_instr = save_ga;
2071 return NULL;
2072 }
2073
2074 // Move the generated instructions into the ISN_SUBSTITUTE
2075 // instructions, then restore the list of instructions before
2076 // adding the ISN_SUBSTITUTE instruction.
2077 instr_count = cctx->ctx_instr.ga_len;
2078 instr = cctx->ctx_instr.ga_data;
2079 instr[instr_count].isn_type = ISN_FINISH;
2080
2081 cctx->ctx_instr = save_ga;
2082 if ((isn = generate_instr(cctx, ISN_SUBSTITUTE)) == NULL)
2083 {
2084 int idx;
2085
2086 for (idx = 0; idx < instr_count; ++idx)
2087 delete_instr(instr + idx);
2088 vim_free(instr);
2089 return NULL;
2090 }
2091 isn->isn_arg.subs.subs_cmd = vim_strsave(arg);
2092 isn->isn_arg.subs.subs_instr = instr;
2093
2094 // skip over flags
2095 if (*end == '&')
2096 ++end;
2097 while (ASCII_ISALPHA(*end) || *end == '#')
2098 ++end;
2099 return end;
2100 }
2101 }
2102
2103 return compile_exec(arg, eap, cctx);
2104}
2105
2106 char_u *
2107compile_redir(char_u *line, exarg_T *eap, cctx_T *cctx)
2108{
2109 char_u *arg = eap->arg;
2110 lhs_T *lhs = &cctx->ctx_redir_lhs;
2111
2112 if (lhs->lhs_name != NULL)
2113 {
2114 if (STRNCMP(arg, "END", 3) == 0)
2115 {
2116 if (lhs->lhs_append)
2117 {
2118 // First load the current variable value.
2119 if (compile_load_lhs_with_index(lhs, lhs->lhs_whole,
2120 cctx) == FAIL)
2121 return NULL;
2122 }
2123
2124 // Gets the redirected text and put it on the stack, then store it
2125 // in the variable.
2126 generate_instr_type(cctx, ISN_REDIREND, &t_string);
2127
2128 if (lhs->lhs_append)
2129 generate_instr_drop(cctx, ISN_CONCAT, 1);
2130
2131 if (lhs->lhs_has_index)
2132 {
2133 // Use the info in "lhs" to store the value at the index in the
2134 // list or dict.
2135 if (compile_assign_unlet(lhs->lhs_whole, lhs, TRUE,
2136 &t_string, cctx) == FAIL)
2137 return NULL;
2138 }
Bram Moolenaar5cd64792021-12-25 18:23:24 +00002139 else if (generate_store_lhs(cctx, lhs, -1, FALSE) == FAIL)
Bram Moolenaardc7c3662021-12-20 15:04:29 +00002140 return NULL;
2141
2142 VIM_CLEAR(lhs->lhs_name);
2143 VIM_CLEAR(lhs->lhs_whole);
2144 return arg + 3;
2145 }
2146 emsg(_(e_cannot_nest_redir));
2147 return NULL;
2148 }
2149
2150 if (arg[0] == '=' && arg[1] == '>')
2151 {
2152 int append = FALSE;
2153
2154 // redirect to a variable is compiled
2155 arg += 2;
2156 if (*arg == '>')
2157 {
2158 ++arg;
2159 append = TRUE;
2160 }
2161 arg = skipwhite(arg);
2162
2163 if (compile_assign_lhs(arg, lhs, CMD_redir,
2164 FALSE, FALSE, 1, cctx) == FAIL)
2165 return NULL;
2166 if (need_type(&t_string, lhs->lhs_member_type,
2167 -1, 0, cctx, FALSE, FALSE) == FAIL)
2168 return NULL;
2169 generate_instr(cctx, ISN_REDIRSTART);
2170 lhs->lhs_append = append;
2171 if (lhs->lhs_has_index)
2172 {
2173 lhs->lhs_whole = vim_strnsave(arg, lhs->lhs_varlen_total);
2174 if (lhs->lhs_whole == NULL)
2175 return NULL;
2176 }
2177
2178 return arg + lhs->lhs_varlen_total;
2179 }
2180
2181 // other redirects are handled like at script level
2182 return compile_exec(line, eap, cctx);
2183}
2184
2185#if defined(FEAT_QUICKFIX) || defined(PROTO)
2186 char_u *
2187compile_cexpr(char_u *line, exarg_T *eap, cctx_T *cctx)
2188{
2189 isn_T *isn;
2190 char_u *p;
2191
2192 isn = generate_instr(cctx, ISN_CEXPR_AUCMD);
2193 if (isn == NULL)
2194 return NULL;
2195 isn->isn_arg.number = eap->cmdidx;
2196
2197 p = eap->arg;
2198 if (compile_expr0(&p, cctx) == FAIL)
2199 return NULL;
2200
2201 isn = generate_instr(cctx, ISN_CEXPR_CORE);
2202 if (isn == NULL)
2203 return NULL;
2204 isn->isn_arg.cexpr.cexpr_ref = ALLOC_ONE(cexprref_T);
2205 if (isn->isn_arg.cexpr.cexpr_ref == NULL)
2206 return NULL;
2207 isn->isn_arg.cexpr.cexpr_ref->cer_cmdidx = eap->cmdidx;
2208 isn->isn_arg.cexpr.cexpr_ref->cer_forceit = eap->forceit;
2209 isn->isn_arg.cexpr.cexpr_ref->cer_cmdline = vim_strsave(skipwhite(line));
2210
2211 return p;
2212}
2213#endif
2214
2215/*
2216 * Compile "return [expr]".
2217 * When "legacy" is TRUE evaluate [expr] with legacy syntax
2218 */
2219 char_u *
2220compile_return(char_u *arg, int check_return_type, int legacy, cctx_T *cctx)
2221{
2222 char_u *p = arg;
Bram Moolenaardc7c3662021-12-20 15:04:29 +00002223 type_T *stack_type;
2224
2225 if (*p != NUL && *p != '|' && *p != '\n')
2226 {
Bram Moolenaar0bfa8492022-01-22 12:27:04 +00002227 // For a lambda, "return expr" is always used, also when "expr" results
2228 // in a void.
2229 if (cctx->ctx_ufunc->uf_ret_type->tt_type == VAR_VOID
2230 && (cctx->ctx_ufunc->uf_flags & FC_LAMBDA) == 0)
Bram Moolenaaref7aadb2022-01-18 18:46:07 +00002231 {
2232 emsg(_(e_returning_value_in_function_without_return_type));
2233 return NULL;
2234 }
Bram Moolenaardc7c3662021-12-20 15:04:29 +00002235 if (legacy)
2236 {
2237 int save_flags = cmdmod.cmod_flags;
2238
2239 generate_LEGACY_EVAL(cctx, p);
2240 if (need_type(&t_any, cctx->ctx_ufunc->uf_ret_type, -1,
2241 0, cctx, FALSE, FALSE) == FAIL)
2242 return NULL;
2243 cmdmod.cmod_flags |= CMOD_LEGACY;
2244 (void)skip_expr(&p, NULL);
2245 cmdmod.cmod_flags = save_flags;
2246 }
2247 else
2248 {
2249 // compile return argument into instructions
2250 if (compile_expr0(&p, cctx) == FAIL)
2251 return NULL;
2252 }
2253
2254 if (cctx->ctx_skip != SKIP_YES)
2255 {
2256 // "check_return_type" with uf_ret_type set to &t_unknown is used
2257 // for an inline function without a specified return type. Set the
2258 // return type here.
Bram Moolenaar078a4612022-01-04 15:17:03 +00002259 stack_type = get_type_on_stack(cctx, 0);
Bram Moolenaardc7c3662021-12-20 15:04:29 +00002260 if ((check_return_type && (cctx->ctx_ufunc->uf_ret_type == NULL
Bram Moolenaar1a572e92022-03-15 12:28:10 +00002261 || cctx->ctx_ufunc->uf_ret_type == &t_unknown))
Bram Moolenaardc7c3662021-12-20 15:04:29 +00002262 || (!check_return_type
2263 && cctx->ctx_ufunc->uf_ret_type == &t_unknown))
2264 {
2265 cctx->ctx_ufunc->uf_ret_type = stack_type;
2266 }
2267 else
2268 {
Bram Moolenaardc7c3662021-12-20 15:04:29 +00002269 if (need_type(stack_type, cctx->ctx_ufunc->uf_ret_type, -1,
2270 0, cctx, FALSE, FALSE) == FAIL)
2271 return NULL;
2272 }
2273 }
2274 }
2275 else
2276 {
2277 // "check_return_type" cannot be TRUE, only used for a lambda which
2278 // always has an argument.
2279 if (cctx->ctx_ufunc->uf_ret_type->tt_type != VAR_VOID
2280 && cctx->ctx_ufunc->uf_ret_type->tt_type != VAR_UNKNOWN)
2281 {
2282 emsg(_(e_missing_return_value));
2283 return NULL;
2284 }
2285
2286 // No argument, return zero.
2287 generate_PUSHNR(cctx, 0);
2288 }
2289
2290 // Undo any command modifiers.
2291 generate_undo_cmdmods(cctx);
2292
2293 if (cctx->ctx_skip != SKIP_YES && generate_instr(cctx, ISN_RETURN) == NULL)
2294 return NULL;
2295
2296 // "return val | endif" is possible
2297 return skipwhite(p);
2298}
2299
2300/*
2301 * Check if the separator for a :global or :substitute command is OK.
2302 */
2303 int
2304check_global_and_subst(char_u *cmd, char_u *arg)
2305{
2306 if (arg == cmd + 1 && vim_strchr((char_u *)":-.", *arg) != NULL)
2307 {
2308 semsg(_(e_separator_not_supported_str), arg);
2309 return FAIL;
2310 }
2311 if (VIM_ISWHITE(cmd[1]))
2312 {
2313 semsg(_(e_no_white_space_allowed_before_separator_str), cmd);
2314 return FAIL;
2315 }
2316 return OK;
2317}
2318
2319
2320#endif // defined(FEAT_EVAL)