comparison src/vim9compile.c @ 23927:5e5780e3f75d v8.2.2506

patch 8.2.2506: Vim9: :continue does not work correctly in a :try block Commit: https://github.com/vim/vim/commit/c150c09ec4f97636c6339f5687fdaa9f665095d2 Author: Bram Moolenaar <Bram@vim.org> Date: Sat Feb 13 15:02:46 2021 +0100 patch 8.2.2506: Vim9: :continue does not work correctly in a :try block Problem: Vim9: :continue does not work correctly in a :try block Solution: Add the TRYCLEANUP instruction. (closes https://github.com/vim/vim/issues/7827)
author Bram Moolenaar <Bram@vim.org>
date Sat, 13 Feb 2021 15:15:03 +0100
parents be36288235af
children 9854b4c6d5e6
comparison
equal deleted inserted replaced
23926:1a41fde53816 23927:5e5780e3f75d
1590 ((type_T **)stack->ga_data)[stack->ga_len] = &t_any; 1590 ((type_T **)stack->ga_data)[stack->ga_len] = &t_any;
1591 ++stack->ga_len; 1591 ++stack->ga_len;
1592 1592
1593 return OK; 1593 return OK;
1594 } 1594 }
1595 /*
1596 * Generate an ISN_TRYCONT instruction.
1597 */
1598 static int
1599 generate_TRYCONT(cctx_T *cctx, int levels, int where)
1600 {
1601 isn_T *isn;
1602
1603 RETURN_OK_IF_SKIP(cctx);
1604 if ((isn = generate_instr(cctx, ISN_TRYCONT)) == NULL)
1605 return FAIL;
1606 isn->isn_arg.trycont.tct_levels = levels;
1607 isn->isn_arg.trycont.tct_where = where;
1608
1609 return OK;
1610 }
1611
1595 1612
1596 /* 1613 /*
1597 * Generate an ISN_BCALL instruction. 1614 * Generate an ISN_BCALL instruction.
1598 * "method_call" is TRUE for "value->method()" 1615 * "method_call" is TRUE for "value->method()"
1599 * Return FAIL if the number of arguments is wrong. 1616 * Return FAIL if the number of arguments is wrong.
7312 */ 7329 */
7313 static char_u * 7330 static char_u *
7314 compile_continue(char_u *arg, cctx_T *cctx) 7331 compile_continue(char_u *arg, cctx_T *cctx)
7315 { 7332 {
7316 scope_T *scope = cctx->ctx_scope; 7333 scope_T *scope = cctx->ctx_scope;
7334 int try_scopes = 0;
7335 int loop_label;
7317 7336
7318 for (;;) 7337 for (;;)
7319 { 7338 {
7320 if (scope == NULL) 7339 if (scope == NULL)
7321 { 7340 {
7322 emsg(_(e_continue)); 7341 emsg(_(e_continue));
7323 return NULL; 7342 return NULL;
7324 } 7343 }
7325 if (scope->se_type == FOR_SCOPE || scope->se_type == WHILE_SCOPE) 7344 if (scope->se_type == FOR_SCOPE)
7345 {
7346 loop_label = scope->se_u.se_for.fs_top_label;
7326 break; 7347 break;
7348 }
7349 if (scope->se_type == WHILE_SCOPE)
7350 {
7351 loop_label = scope->se_u.se_while.ws_top_label;
7352 break;
7353 }
7354 if (scope->se_type == TRY_SCOPE)
7355 ++try_scopes;
7327 scope = scope->se_outer; 7356 scope = scope->se_outer;
7328 } 7357 }
7329 7358
7330 // Jump back to the FOR or WHILE instruction. 7359 if (try_scopes > 0)
7331 generate_JUMP(cctx, JUMP_ALWAYS, 7360 // Inside one or more try/catch blocks we first need to jump to the
7332 scope->se_type == FOR_SCOPE ? scope->se_u.se_for.fs_top_label 7361 // "finally" or "endtry" to cleanup.
7333 : scope->se_u.se_while.ws_top_label); 7362 generate_TRYCONT(cctx, try_scopes, loop_label);
7363 else
7364 // Jump back to the FOR or WHILE instruction.
7365 generate_JUMP(cctx, JUMP_ALWAYS, loop_label);
7366
7334 return arg; 7367 return arg;
7335 } 7368 }
7336 7369
7337 /* 7370 /*
7338 * compile "break" 7371 * compile "break"
7623 static char_u * 7656 static char_u *
7624 compile_endtry(char_u *arg, cctx_T *cctx) 7657 compile_endtry(char_u *arg, cctx_T *cctx)
7625 { 7658 {
7626 scope_T *scope = cctx->ctx_scope; 7659 scope_T *scope = cctx->ctx_scope;
7627 garray_T *instr = &cctx->ctx_instr; 7660 garray_T *instr = &cctx->ctx_instr;
7628 isn_T *isn; 7661 isn_T *try_isn;
7629 7662
7630 // end block scope from :catch or :finally 7663 // end block scope from :catch or :finally
7631 if (scope != NULL && scope->se_type == BLOCK_SCOPE) 7664 if (scope != NULL && scope->se_type == BLOCK_SCOPE)
7632 compile_endblock(cctx); 7665 compile_endblock(cctx);
7633 scope = cctx->ctx_scope; 7666 scope = cctx->ctx_scope;
7644 else 7677 else
7645 emsg(_(e_endif)); 7678 emsg(_(e_endif));
7646 return NULL; 7679 return NULL;
7647 } 7680 }
7648 7681
7682 try_isn = ((isn_T *)instr->ga_data) + scope->se_u.se_try.ts_try_label;
7649 if (cctx->ctx_skip != SKIP_YES) 7683 if (cctx->ctx_skip != SKIP_YES)
7650 { 7684 {
7651 isn = ((isn_T *)instr->ga_data) + scope->se_u.se_try.ts_try_label; 7685 if (try_isn->isn_arg.try.try_catch == 0
7652 if (isn->isn_arg.try.try_catch == 0 7686 && try_isn->isn_arg.try.try_finally == 0)
7653 && isn->isn_arg.try.try_finally == 0)
7654 { 7687 {
7655 emsg(_(e_missing_catch_or_finally)); 7688 emsg(_(e_missing_catch_or_finally));
7656 return NULL; 7689 return NULL;
7657 } 7690 }
7658 7691
7668 // done by ":finally". 7701 // done by ":finally".
7669 compile_fill_jump_to_end(&scope->se_u.se_try.ts_end_label, 7702 compile_fill_jump_to_end(&scope->se_u.se_try.ts_end_label,
7670 instr->ga_len, cctx); 7703 instr->ga_len, cctx);
7671 7704
7672 // End :catch or :finally scope: set value in ISN_TRY instruction 7705 // End :catch or :finally scope: set value in ISN_TRY instruction
7673 if (isn->isn_arg.try.try_catch == 0) 7706 if (try_isn->isn_arg.try.try_catch == 0)
7674 isn->isn_arg.try.try_catch = instr->ga_len; 7707 try_isn->isn_arg.try.try_catch = instr->ga_len;
7675 if (isn->isn_arg.try.try_finally == 0) 7708 if (try_isn->isn_arg.try.try_finally == 0)
7676 isn->isn_arg.try.try_finally = instr->ga_len; 7709 try_isn->isn_arg.try.try_finally = instr->ga_len;
7677 7710
7678 if (scope->se_u.se_try.ts_catch_label != 0) 7711 if (scope->se_u.se_try.ts_catch_label != 0)
7679 { 7712 {
7680 // Last catch without match jumps here 7713 // Last catch without match jumps here
7681 isn = ((isn_T *)instr->ga_data) + scope->se_u.se_try.ts_catch_label; 7714 isn_T *isn = ((isn_T *)instr->ga_data)
7715 + scope->se_u.se_try.ts_catch_label;
7682 isn->isn_arg.jump.jump_where = instr->ga_len; 7716 isn->isn_arg.jump.jump_where = instr->ga_len;
7683 } 7717 }
7684 } 7718 }
7685 7719
7686 compile_endblock(cctx); 7720 compile_endblock(cctx);
7721
7722 if (try_isn->isn_arg.try.try_finally == 0)
7723 // No :finally encountered, use the try_finaly field to point to
7724 // ENDTRY, so that TRYCONT can jump there.
7725 try_isn->isn_arg.try.try_finally = cctx->ctx_instr.ga_len;
7687 7726
7688 if (cctx->ctx_skip != SKIP_YES && generate_instr(cctx, ISN_ENDTRY) == NULL) 7727 if (cctx->ctx_skip != SKIP_YES && generate_instr(cctx, ISN_ENDTRY) == NULL)
7689 return NULL; 7728 return NULL;
7690 #ifdef FEAT_PROFILE 7729 #ifdef FEAT_PROFILE
7691 if (cctx->ctx_profiling) 7730 if (cctx->ctx_profiling)
8848 case ISN_STOREV: 8887 case ISN_STOREV:
8849 case ISN_STRINDEX: 8888 case ISN_STRINDEX:
8850 case ISN_STRSLICE: 8889 case ISN_STRSLICE:
8851 case ISN_THROW: 8890 case ISN_THROW:
8852 case ISN_TRY: 8891 case ISN_TRY:
8892 case ISN_TRYCONT:
8853 case ISN_UNLETINDEX: 8893 case ISN_UNLETINDEX:
8854 case ISN_UNPACK: 8894 case ISN_UNPACK:
8855 // nothing allocated 8895 // nothing allocated
8856 break; 8896 break;
8857 } 8897 }