@@ -1592,6 +1592,23 @@ generate_FOR(cctx_T *cctx, int loop_idx)
15921592
15931593 return OK ;
15941594}
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+
15951612
15961613/*
15971614 * Generate an ISN_BCALL instruction.
@@ -7314,6 +7331,8 @@ compile_endwhile(char_u *arg, cctx_T *cctx)
73147331compile_continue (char_u * arg , cctx_T * cctx )
73157332{
73167333 scope_T * scope = cctx -> ctx_scope ;
7334+ int try_scopes = 0 ;
7335+ int loop_label ;
73177336
73187337 for (;;)
73197338 {
@@ -7322,15 +7341,29 @@ compile_continue(char_u *arg, cctx_T *cctx)
73227341 emsg (_ (e_continue ));
73237342 return NULL ;
73247343 }
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 ;
7347+ break ;
7348+ }
7349+ if (scope -> se_type == WHILE_SCOPE )
7350+ {
7351+ loop_label = scope -> se_u .se_while .ws_top_label ;
73267352 break ;
7353+ }
7354+ if (scope -> se_type == TRY_SCOPE )
7355+ ++ try_scopes ;
73277356 scope = scope -> se_outer ;
73287357 }
73297358
7330- // Jump back to the FOR or WHILE instruction.
7331- generate_JUMP (cctx , JUMP_ALWAYS ,
7332- scope -> se_type == FOR_SCOPE ? scope -> se_u .se_for .fs_top_label
7333- : scope -> se_u .se_while .ws_top_label );
7359+ if (try_scopes > 0 )
7360+ // Inside one or more try/catch blocks we first need to jump to the
7361+ // "finally" or "endtry" to cleanup.
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+
73347367 return arg ;
73357368}
73367369
@@ -7625,7 +7658,7 @@ compile_endtry(char_u *arg, cctx_T *cctx)
76257658{
76267659 scope_T * scope = cctx -> ctx_scope ;
76277660 garray_T * instr = & cctx -> ctx_instr ;
7628- isn_T * isn ;
7661+ isn_T * try_isn ;
76297662
76307663 // end block scope from :catch or :finally
76317664 if (scope != NULL && scope -> se_type == BLOCK_SCOPE )
@@ -7646,11 +7679,11 @@ compile_endtry(char_u *arg, cctx_T *cctx)
76467679 return NULL ;
76477680 }
76487681
7682+ try_isn = ((isn_T * )instr -> ga_data ) + scope -> se_u .se_try .ts_try_label ;
76497683 if (cctx -> ctx_skip != SKIP_YES )
76507684 {
7651- isn = ((isn_T * )instr -> ga_data ) + scope -> se_u .se_try .ts_try_label ;
7652- if (isn -> isn_arg .try .try_catch == 0
7653- && isn -> isn_arg .try .try_finally == 0 )
7685+ if (try_isn -> isn_arg .try .try_catch == 0
7686+ && try_isn -> isn_arg .try .try_finally == 0 )
76547687 {
76557688 emsg (_ (e_missing_catch_or_finally ));
76567689 return NULL ;
@@ -7670,21 +7703,27 @@ compile_endtry(char_u *arg, cctx_T *cctx)
76707703 instr -> ga_len , cctx );
76717704
76727705 // End :catch or :finally scope: set value in ISN_TRY instruction
7673- if (isn -> isn_arg .try .try_catch == 0 )
7674- isn -> isn_arg .try .try_catch = instr -> ga_len ;
7675- if (isn -> isn_arg .try .try_finally == 0 )
7676- isn -> isn_arg .try .try_finally = instr -> ga_len ;
7706+ if (try_isn -> isn_arg .try .try_catch == 0 )
7707+ try_isn -> isn_arg .try .try_catch = instr -> ga_len ;
7708+ if (try_isn -> isn_arg .try .try_finally == 0 )
7709+ try_isn -> isn_arg .try .try_finally = instr -> ga_len ;
76777710
76787711 if (scope -> se_u .se_try .ts_catch_label != 0 )
76797712 {
76807713 // 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 ;
76827716 isn -> isn_arg .jump .jump_where = instr -> ga_len ;
76837717 }
76847718 }
76857719
76867720 compile_endblock (cctx );
76877721
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 ;
7726+
76887727 if (cctx -> ctx_skip != SKIP_YES && generate_instr (cctx , ISN_ENDTRY ) == NULL )
76897728 return NULL ;
76907729#ifdef FEAT_PROFILE
@@ -8850,6 +8889,7 @@ delete_instr(isn_T *isn)
88508889 case ISN_STRSLICE :
88518890 case ISN_THROW :
88528891 case ISN_TRY :
8892+ case ISN_TRYCONT :
88538893 case ISN_UNLETINDEX :
88548894 case ISN_UNPACK :
88558895 // nothing allocated
0 commit comments