Mercurial > vim
comparison 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 |
comparison
equal
deleted
inserted
replaced
23926:1a41fde53816 | 23927:5e5780e3f75d |
---|---|
25 // Structure put on ec_trystack when ISN_TRY is encountered. | 25 // Structure put on ec_trystack when ISN_TRY is encountered. |
26 typedef struct { | 26 typedef struct { |
27 int tcd_frame_idx; // ec_frame_idx at ISN_TRY | 27 int tcd_frame_idx; // ec_frame_idx at ISN_TRY |
28 int tcd_stack_len; // size of ectx.ec_stack at ISN_TRY | 28 int tcd_stack_len; // size of ectx.ec_stack at ISN_TRY |
29 int tcd_catch_idx; // instruction of the first catch | 29 int tcd_catch_idx; // instruction of the first catch |
30 int tcd_finally_idx; // instruction of the finally block | 30 int tcd_finally_idx; // instruction of the finally block or :endtry |
31 int tcd_caught; // catch block entered | 31 int tcd_caught; // catch block entered |
32 int tcd_cont; // :continue encountered, jump here | |
32 int tcd_return; // when TRUE return from end of :finally | 33 int tcd_return; // when TRUE return from end of :finally |
33 } trycmd_T; | 34 } trycmd_T; |
34 | 35 |
35 | 36 |
36 // A stack is used to store: | 37 // A stack is used to store: |
2415 if (trystack->ga_len > 0) | 2416 if (trystack->ga_len > 0) |
2416 trycmd = ((trycmd_T *)trystack->ga_data) | 2417 trycmd = ((trycmd_T *)trystack->ga_data) |
2417 + trystack->ga_len - 1; | 2418 + trystack->ga_len - 1; |
2418 if (trycmd != NULL | 2419 if (trycmd != NULL |
2419 && trycmd->tcd_frame_idx == ectx.ec_frame_idx | 2420 && trycmd->tcd_frame_idx == ectx.ec_frame_idx |
2420 && trycmd->tcd_finally_idx != 0) | 2421 && ectx.ec_instr[trycmd->tcd_finally_idx] |
2422 .isn_type != ISN_ENDTRY) | |
2421 { | 2423 { |
2422 // jump to ":finally" | 2424 // jump to ":finally" |
2423 ectx.ec_iidx = trycmd->tcd_finally_idx; | 2425 ectx.ec_iidx = trycmd->tcd_finally_idx; |
2424 trycmd->tcd_return = TRUE; | 2426 trycmd->tcd_return = TRUE; |
2425 } | 2427 } |
2608 force_abort = need_rethrow = FALSE; | 2610 force_abort = need_rethrow = FALSE; |
2609 catch_exception(current_exception); | 2611 catch_exception(current_exception); |
2610 } | 2612 } |
2611 break; | 2613 break; |
2612 | 2614 |
2615 case ISN_TRYCONT: | |
2616 { | |
2617 garray_T *trystack = &ectx.ec_trystack; | |
2618 trycont_T *trycont = &iptr->isn_arg.trycont; | |
2619 int i; | |
2620 trycmd_T *trycmd; | |
2621 int iidx = trycont->tct_where; | |
2622 | |
2623 if (trystack->ga_len < trycont->tct_levels) | |
2624 { | |
2625 siemsg("TRYCONT: expected %d levels, found %d", | |
2626 trycont->tct_levels, trystack->ga_len); | |
2627 goto failed; | |
2628 } | |
2629 // Make :endtry jump to any outer try block and the last | |
2630 // :endtry inside the loop to the loop start. | |
2631 for (i = trycont->tct_levels; i > 0; --i) | |
2632 { | |
2633 trycmd = ((trycmd_T *)trystack->ga_data) | |
2634 + trystack->ga_len - i; | |
2635 trycmd->tcd_cont = iidx; | |
2636 iidx = trycmd->tcd_finally_idx; | |
2637 } | |
2638 // jump to :finally or :endtry of current try statement | |
2639 ectx.ec_iidx = iidx; | |
2640 } | |
2641 break; | |
2642 | |
2613 // end of ":try" block | 2643 // end of ":try" block |
2614 case ISN_ENDTRY: | 2644 case ISN_ENDTRY: |
2615 { | 2645 { |
2616 garray_T *trystack = &ectx.ec_trystack; | 2646 garray_T *trystack = &ectx.ec_trystack; |
2617 | 2647 |
2638 while (ectx.ec_stack.ga_len > trycmd->tcd_stack_len) | 2668 while (ectx.ec_stack.ga_len > trycmd->tcd_stack_len) |
2639 { | 2669 { |
2640 --ectx.ec_stack.ga_len; | 2670 --ectx.ec_stack.ga_len; |
2641 clear_tv(STACK_TV_BOT(0)); | 2671 clear_tv(STACK_TV_BOT(0)); |
2642 } | 2672 } |
2673 if (trycmd->tcd_cont) | |
2674 // handling :continue: jump to outer try block or | |
2675 // start of the loop | |
2676 ectx.ec_iidx = trycmd->tcd_cont; | |
2643 } | 2677 } |
2644 } | 2678 } |
2645 break; | 2679 break; |
2646 | 2680 |
2647 case ISN_THROW: | 2681 case ISN_THROW: |
4211 | 4245 |
4212 case ISN_TRY: | 4246 case ISN_TRY: |
4213 { | 4247 { |
4214 try_T *try = &iptr->isn_arg.try; | 4248 try_T *try = &iptr->isn_arg.try; |
4215 | 4249 |
4216 smsg("%4d TRY catch -> %d, finally -> %d", current, | 4250 smsg("%4d TRY catch -> %d, %s -> %d", current, |
4217 try->try_catch, try->try_finally); | 4251 try->try_catch, |
4252 instr[try->try_finally].isn_type == ISN_ENDTRY | |
4253 ? "end" : "finally", | |
4254 try->try_finally); | |
4218 } | 4255 } |
4219 break; | 4256 break; |
4220 case ISN_CATCH: | 4257 case ISN_CATCH: |
4221 // TODO | 4258 // TODO |
4222 smsg("%4d CATCH", current); | 4259 smsg("%4d CATCH", current); |
4260 break; | |
4261 case ISN_TRYCONT: | |
4262 { | |
4263 trycont_T *trycont = &iptr->isn_arg.trycont; | |
4264 | |
4265 smsg("%4d TRY-CONTINUE %d level%s -> %d", current, | |
4266 trycont->tct_levels, | |
4267 trycont->tct_levels == 1 ? "" : "s", | |
4268 trycont->tct_where); | |
4269 } | |
4223 break; | 4270 break; |
4224 case ISN_ENDTRY: | 4271 case ISN_ENDTRY: |
4225 smsg("%4d ENDTRY", current); | 4272 smsg("%4d ENDTRY", current); |
4226 break; | 4273 break; |
4227 case ISN_THROW: | 4274 case ISN_THROW: |