Mercurial > vim
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 } |