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