mirror of
https://github.com/vim/vim.git
synced 2025-09-23 03:43:49 -04:00
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 #7827)
This commit is contained in:
@@ -1592,6 +1592,23 @@ generate_FOR(cctx_T *cctx, int loop_idx)
|
||||
|
||||
return OK;
|
||||
}
|
||||
/*
|
||||
* Generate an ISN_TRYCONT instruction.
|
||||
*/
|
||||
static int
|
||||
generate_TRYCONT(cctx_T *cctx, int levels, int where)
|
||||
{
|
||||
isn_T *isn;
|
||||
|
||||
RETURN_OK_IF_SKIP(cctx);
|
||||
if ((isn = generate_instr(cctx, ISN_TRYCONT)) == NULL)
|
||||
return FAIL;
|
||||
isn->isn_arg.trycont.tct_levels = levels;
|
||||
isn->isn_arg.trycont.tct_where = where;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Generate an ISN_BCALL instruction.
|
||||
@@ -7314,6 +7331,8 @@ compile_endwhile(char_u *arg, cctx_T *cctx)
|
||||
compile_continue(char_u *arg, cctx_T *cctx)
|
||||
{
|
||||
scope_T *scope = cctx->ctx_scope;
|
||||
int try_scopes = 0;
|
||||
int loop_label;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
@@ -7322,15 +7341,29 @@ compile_continue(char_u *arg, cctx_T *cctx)
|
||||
emsg(_(e_continue));
|
||||
return NULL;
|
||||
}
|
||||
if (scope->se_type == FOR_SCOPE || scope->se_type == WHILE_SCOPE)
|
||||
if (scope->se_type == FOR_SCOPE)
|
||||
{
|
||||
loop_label = scope->se_u.se_for.fs_top_label;
|
||||
break;
|
||||
}
|
||||
if (scope->se_type == WHILE_SCOPE)
|
||||
{
|
||||
loop_label = scope->se_u.se_while.ws_top_label;
|
||||
break;
|
||||
}
|
||||
if (scope->se_type == TRY_SCOPE)
|
||||
++try_scopes;
|
||||
scope = scope->se_outer;
|
||||
}
|
||||
|
||||
// Jump back to the FOR or WHILE instruction.
|
||||
generate_JUMP(cctx, JUMP_ALWAYS,
|
||||
scope->se_type == FOR_SCOPE ? scope->se_u.se_for.fs_top_label
|
||||
: scope->se_u.se_while.ws_top_label);
|
||||
if (try_scopes > 0)
|
||||
// Inside one or more try/catch blocks we first need to jump to the
|
||||
// "finally" or "endtry" to cleanup.
|
||||
generate_TRYCONT(cctx, try_scopes, loop_label);
|
||||
else
|
||||
// Jump back to the FOR or WHILE instruction.
|
||||
generate_JUMP(cctx, JUMP_ALWAYS, loop_label);
|
||||
|
||||
return arg;
|
||||
}
|
||||
|
||||
@@ -7625,7 +7658,7 @@ compile_endtry(char_u *arg, cctx_T *cctx)
|
||||
{
|
||||
scope_T *scope = cctx->ctx_scope;
|
||||
garray_T *instr = &cctx->ctx_instr;
|
||||
isn_T *isn;
|
||||
isn_T *try_isn;
|
||||
|
||||
// end block scope from :catch or :finally
|
||||
if (scope != NULL && scope->se_type == BLOCK_SCOPE)
|
||||
@@ -7646,11 +7679,11 @@ compile_endtry(char_u *arg, cctx_T *cctx)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
try_isn = ((isn_T *)instr->ga_data) + scope->se_u.se_try.ts_try_label;
|
||||
if (cctx->ctx_skip != SKIP_YES)
|
||||
{
|
||||
isn = ((isn_T *)instr->ga_data) + scope->se_u.se_try.ts_try_label;
|
||||
if (isn->isn_arg.try.try_catch == 0
|
||||
&& isn->isn_arg.try.try_finally == 0)
|
||||
if (try_isn->isn_arg.try.try_catch == 0
|
||||
&& try_isn->isn_arg.try.try_finally == 0)
|
||||
{
|
||||
emsg(_(e_missing_catch_or_finally));
|
||||
return NULL;
|
||||
@@ -7670,21 +7703,27 @@ compile_endtry(char_u *arg, cctx_T *cctx)
|
||||
instr->ga_len, cctx);
|
||||
|
||||
// End :catch or :finally scope: set value in ISN_TRY instruction
|
||||
if (isn->isn_arg.try.try_catch == 0)
|
||||
isn->isn_arg.try.try_catch = instr->ga_len;
|
||||
if (isn->isn_arg.try.try_finally == 0)
|
||||
isn->isn_arg.try.try_finally = instr->ga_len;
|
||||
if (try_isn->isn_arg.try.try_catch == 0)
|
||||
try_isn->isn_arg.try.try_catch = instr->ga_len;
|
||||
if (try_isn->isn_arg.try.try_finally == 0)
|
||||
try_isn->isn_arg.try.try_finally = instr->ga_len;
|
||||
|
||||
if (scope->se_u.se_try.ts_catch_label != 0)
|
||||
{
|
||||
// Last catch without match jumps here
|
||||
isn = ((isn_T *)instr->ga_data) + scope->se_u.se_try.ts_catch_label;
|
||||
isn_T *isn = ((isn_T *)instr->ga_data)
|
||||
+ scope->se_u.se_try.ts_catch_label;
|
||||
isn->isn_arg.jump.jump_where = instr->ga_len;
|
||||
}
|
||||
}
|
||||
|
||||
compile_endblock(cctx);
|
||||
|
||||
if (try_isn->isn_arg.try.try_finally == 0)
|
||||
// No :finally encountered, use the try_finaly field to point to
|
||||
// ENDTRY, so that TRYCONT can jump there.
|
||||
try_isn->isn_arg.try.try_finally = cctx->ctx_instr.ga_len;
|
||||
|
||||
if (cctx->ctx_skip != SKIP_YES && generate_instr(cctx, ISN_ENDTRY) == NULL)
|
||||
return NULL;
|
||||
#ifdef FEAT_PROFILE
|
||||
@@ -8850,6 +8889,7 @@ delete_instr(isn_T *isn)
|
||||
case ISN_STRSLICE:
|
||||
case ISN_THROW:
|
||||
case ISN_TRY:
|
||||
case ISN_TRYCONT:
|
||||
case ISN_UNLETINDEX:
|
||||
case ISN_UNPACK:
|
||||
// nothing allocated
|
||||
|
Reference in New Issue
Block a user