Mercurial > vim
diff src/vim9execute.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 | a834f9c082e3 |
children | f9a4ede76237 |
line wrap: on
line diff
--- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -27,8 +27,9 @@ typedef struct { int tcd_frame_idx; // ec_frame_idx at ISN_TRY int tcd_stack_len; // size of ectx.ec_stack at ISN_TRY int tcd_catch_idx; // instruction of the first catch - int tcd_finally_idx; // instruction of the finally block + int tcd_finally_idx; // instruction of the finally block or :endtry int tcd_caught; // catch block entered + int tcd_cont; // :continue encountered, jump here int tcd_return; // when TRUE return from end of :finally } trycmd_T; @@ -2417,7 +2418,8 @@ call_def_function( + trystack->ga_len - 1; if (trycmd != NULL && trycmd->tcd_frame_idx == ectx.ec_frame_idx - && trycmd->tcd_finally_idx != 0) + && ectx.ec_instr[trycmd->tcd_finally_idx] + .isn_type != ISN_ENDTRY) { // jump to ":finally" ectx.ec_iidx = trycmd->tcd_finally_idx; @@ -2610,6 +2612,34 @@ call_def_function( } break; + case ISN_TRYCONT: + { + garray_T *trystack = &ectx.ec_trystack; + trycont_T *trycont = &iptr->isn_arg.trycont; + int i; + trycmd_T *trycmd; + int iidx = trycont->tct_where; + + if (trystack->ga_len < trycont->tct_levels) + { + siemsg("TRYCONT: expected %d levels, found %d", + trycont->tct_levels, trystack->ga_len); + goto failed; + } + // Make :endtry jump to any outer try block and the last + // :endtry inside the loop to the loop start. + for (i = trycont->tct_levels; i > 0; --i) + { + trycmd = ((trycmd_T *)trystack->ga_data) + + trystack->ga_len - i; + trycmd->tcd_cont = iidx; + iidx = trycmd->tcd_finally_idx; + } + // jump to :finally or :endtry of current try statement + ectx.ec_iidx = iidx; + } + break; + // end of ":try" block case ISN_ENDTRY: { @@ -2640,6 +2670,10 @@ call_def_function( --ectx.ec_stack.ga_len; clear_tv(STACK_TV_BOT(0)); } + if (trycmd->tcd_cont) + // handling :continue: jump to outer try block or + // start of the loop + ectx.ec_iidx = trycmd->tcd_cont; } } break; @@ -4213,14 +4247,27 @@ ex_disassemble(exarg_T *eap) { try_T *try = &iptr->isn_arg.try; - smsg("%4d TRY catch -> %d, finally -> %d", current, - try->try_catch, try->try_finally); + smsg("%4d TRY catch -> %d, %s -> %d", current, + try->try_catch, + instr[try->try_finally].isn_type == ISN_ENDTRY + ? "end" : "finally", + try->try_finally); } break; case ISN_CATCH: // TODO smsg("%4d CATCH", current); break; + case ISN_TRYCONT: + { + trycont_T *trycont = &iptr->isn_arg.trycont; + + smsg("%4d TRY-CONTINUE %d level%s -> %d", current, + trycont->tct_levels, + trycont->tct_levels == 1 ? "" : "s", + trycont->tct_where); + } + break; case ISN_ENDTRY: smsg("%4d ENDTRY", current); break;