*: Replace did_throw checks with current_exception checks

Removes obsolete did_throw after that.
This commit is contained in:
ZyX
2018-03-25 15:13:05 +03:00
parent 79b4b6fc86
commit 201a4ef11c
5 changed files with 209 additions and 246 deletions

View File

@@ -45,22 +45,21 @@
* there or even outside the try conditional. Try conditionals may be nested.
*/
/*
* Configuration whether an exception is thrown on error or interrupt. When
* the preprocessor macros below evaluate to FALSE, an error (did_emsg) or
* interrupt (got_int) under an active try conditional terminates the script
* after the non-active finally clauses of all active try conditionals have been
* executed. Otherwise, errors and/or interrupts are converted into catchable
* exceptions (did_throw additionally set), which terminate the script only if
* not caught. For user exceptions, only did_throw is set. (Note: got_int can
* be set asynchronously afterwards by a SIGINT, so did_throw && got_int is not
* a reliant test that the exception currently being thrown is an interrupt
* exception. Similarly, did_emsg can be set afterwards on an error in an
* (unskipped) conditional command inside an inactive conditional, so did_throw
* && did_emsg is not a reliant test that the exception currently being thrown
* is an error exception.) - The macros can be defined as expressions checking
* for a variable that is allowed to be changed during execution of a script.
*/
// Configuration whether an exception is thrown on error or interrupt. When
// the preprocessor macros below evaluate to FALSE, an error (did_emsg) or
// interrupt (got_int) under an active try conditional terminates the script
// after the non-active finally clauses of all active try conditionals have been
// executed. Otherwise, errors and/or interrupts are converted into catchable
// exceptions, which terminate the script only if not caught. For user
// exceptions, only current_exception is set. (Note: got_int can be set
// asynchronously afterwards by a SIGINT, so current_exception && got_int is not
// a reliant test that the exception currently being thrown is an interrupt
// exception. Similarly, did_emsg can be set afterwards on an error in an
// (unskipped) conditional command inside an inactive conditional, so
// current_exception && did_emsg is not a reliant test that the exception
// currently being thrown is an error exception.) - The macros can be defined
// as expressions checking for a variable that is allowed to be changed during
// execution of a script.
// Values used for the Vim release.
#define THROW_ON_ERROR true
@@ -68,6 +67,15 @@
#define THROW_ON_INTERRUPT true
#define THROW_ON_INTERRUPT_TRUE
// Don't do something after an error, interrupt, or throw, or when
// there is a surrounding conditional and it was not active.
#define CHECK_SKIP \
(did_emsg \
|| got_int \
|| current_exception \
|| (cstack->cs_idx > 0 \
&& !(cstack->cs_flags[cstack->cs_idx - 1] & CSF_ACTIVE)))
#define discard_pending_return(p) tv_free((typval_T *)(p))
/*
@@ -94,7 +102,7 @@ static int cause_abort = FALSE;
*/
int aborting(void)
{
return (did_emsg && force_abort) || got_int || did_throw;
return (did_emsg && force_abort) || got_int || current_exception;
}
/*
@@ -178,8 +186,9 @@ int cause_errthrow(char_u *mesg, int severe, int *ignore)
* currently throwing an exception, do nothing. The message text will
* then be stored to v:errmsg by emsg() without displaying it.
*/
if (((trylevel == 0 && !cause_abort) || emsg_silent) && !did_throw)
return FALSE;
if (((trylevel == 0 && !cause_abort) || emsg_silent) && !current_exception) {
return false;
}
/*
* Ignore an interrupt message when inside a try conditional or when an
@@ -208,12 +217,13 @@ int cause_errthrow(char_u *mesg, int severe, int *ignore)
* exception currently being thrown to prevent it from being caught. Just
* execute finally clauses and terminate.
*/
if (did_throw) {
/* When discarding an interrupt exception, reset got_int to prevent the
* same interrupt being converted to an exception again and discarding
* the error exception we are about to throw here. */
if (current_exception->type == ET_INTERRUPT)
got_int = FALSE;
if (current_exception) {
// When discarding an interrupt exception, reset got_int to prevent the
// same interrupt being converted to an exception again and discarding
// the error exception we are about to throw here.
if (current_exception->type == ET_INTERRUPT) {
got_int = false;
}
discard_current_exception();
}
@@ -333,45 +343,44 @@ void do_errthrow(struct condstack *cstack, char_u *cmdname)
*/
int do_intthrow(struct condstack *cstack)
{
/*
* If no interrupt occurred or no try conditional is active and no exception
* is being thrown, do nothing (for compatibility of non-EH scripts).
*/
if (!got_int || (trylevel == 0 && !did_throw))
return FALSE;
#ifdef THROW_TEST /* avoid warning for condition always true */
if (!THROW_ON_INTERRUPT) {
/*
* The interrupt aborts everything except for executing finally clauses.
* Discard any user or error or interrupt exception currently being
* thrown.
*/
if (did_throw)
discard_current_exception();
} else
#endif
{
/*
* Throw an interrupt exception, so that everything will be aborted
* (except for executing finally clauses), until the interrupt exception
* is caught; if still uncaught at the top level, the script processing
* will be terminated then. - If an interrupt exception is already
* being thrown, do nothing.
*
*/
if (did_throw) {
if (current_exception->type == ET_INTERRUPT)
return FALSE;
/* An interrupt exception replaces any user or error exception. */
discard_current_exception();
}
if (throw_exception("Vim:Interrupt", ET_INTERRUPT, NULL) != FAIL)
do_throw(cstack);
// If no interrupt occurred or no try conditional is active and no exception
// is being thrown, do nothing (for compatibility of non-EH scripts).
if (!got_int || (trylevel == 0 && !current_exception)) {
return false;
}
return TRUE;
#ifdef THROW_TEST // avoid warning for condition always true
if (!THROW_ON_INTERRUPT) {
// The interrupt aborts everything except for executing finally clauses.
// Discard any user or error or interrupt exception currently being
// thrown.
if (current_exception) {
discard_current_exception();
}
} else {
#endif
// Throw an interrupt exception, so that everything will be aborted
// (except for executing finally clauses), until the interrupt exception
// is caught; if still uncaught at the top level, the script processing
// will be terminated then. - If an interrupt exception is already
// being thrown, do nothing.
if (current_exception) {
if (current_exception->type == ET_INTERRUPT) {
return false;
}
// An interrupt exception replaces any user or error exception.
discard_current_exception();
}
if (throw_exception("Vim:Interrupt", ET_INTERRUPT, NULL) != FAIL) {
do_throw(cstack);
}
#ifdef THROW_TEST
}
#endif
return true;
}
// Get an exception message that is to be stored in current_exception->value.
@@ -565,8 +574,7 @@ void discard_current_exception(void)
// Note: all globals manipulated here should be saved/restored in
// try_enter/try_leave.
current_exception = NULL;
did_throw = FALSE;
need_rethrow = FALSE;
need_rethrow = false;
}
/*
@@ -795,15 +803,7 @@ void ex_if(exarg_T *eap)
++cstack->cs_idx;
cstack->cs_flags[cstack->cs_idx] = 0;
/*
* Don't do something after an error, interrupt, or throw, or when there
* is a surrounding conditional and it was not active.
*/
skip = did_emsg || got_int || did_throw || (cstack->cs_idx > 0
&& !(cstack->cs_flags[cstack->
cs_idx -
1] &
CSF_ACTIVE));
skip = CHECK_SKIP;
bool error;
result = eval_to_bool(eap->arg, &error, &eap->nextcmd, skip);
@@ -854,15 +854,7 @@ void ex_else(exarg_T *eap)
int result;
struct condstack *cstack = eap->cstack;
/*
* Don't do something after an error, interrupt, or throw, or when there is
* a surrounding conditional and it was not active.
*/
skip = did_emsg || got_int || did_throw || (cstack->cs_idx > 0
&& !(cstack->cs_flags[cstack->
cs_idx -
1] &
CSF_ACTIVE));
skip = CHECK_SKIP;
if (cstack->cs_idx < 0
|| (cstack->cs_flags[cstack->cs_idx]
@@ -952,15 +944,7 @@ void ex_while(exarg_T *eap)
cstack->cs_flags[cstack->cs_idx] =
eap->cmdidx == CMD_while ? CSF_WHILE : CSF_FOR;
/*
* Don't do something after an error, interrupt, or throw, or when
* there is a surrounding conditional and it was not active.
*/
skip = did_emsg || got_int || did_throw || (cstack->cs_idx > 0
&& !(cstack->cs_flags[cstack->
cs_idx -
1] &
CSF_ACTIVE));
skip = CHECK_SKIP;
if (eap->cmdidx == CMD_while) {
/*
* ":while bool-expr"
@@ -1233,8 +1217,6 @@ void do_throw(struct condstack *cstack)
cstack->cs_flags[idx] &= ~CSF_ACTIVE;
cstack->cs_exception[idx] = current_exception;
}
did_throw = TRUE;
}
/*
@@ -1253,15 +1235,7 @@ void ex_try(exarg_T *eap)
cstack->cs_flags[cstack->cs_idx] = CSF_TRY;
cstack->cs_pending[cstack->cs_idx] = CSTP_NONE;
/*
* Don't do something after an error, interrupt, or throw, or when there
* is a surrounding conditional and it was not active.
*/
skip = did_emsg || got_int || did_throw || (cstack->cs_idx > 0
&& !(cstack->cs_flags[cstack->
cs_idx -
1] &
CSF_ACTIVE));
skip = CHECK_SKIP;
if (!skip) {
/* Set ACTIVE and TRUE. TRUE means that the corresponding ":catch"
@@ -1353,8 +1327,9 @@ void ex_catch(exarg_T *eap)
* corresponding try block never got active (because of an inactive
* surrounding conditional or after an error or interrupt or throw).
*/
if (!did_throw || !(cstack->cs_flags[idx] & CSF_TRUE))
skip = TRUE;
if (!current_exception || !(cstack->cs_flags[idx] & CSF_TRUE)) {
skip = true;
}
/*
* Check for a match only if an exception is thrown but not caught by
@@ -1413,10 +1388,10 @@ void ex_catch(exarg_T *eap)
}
if (caught) {
/* Make this ":catch" clause active and reset did_emsg, got_int,
* and did_throw. Put the exception on the caught stack. */
/* Make this ":catch" clause active and reset did_emsg and got_int.
* Put the exception on the caught stack. */
cstack->cs_flags[idx] |= CSF_ACTIVE | CSF_CAUGHT;
did_emsg = got_int = did_throw = FALSE;
did_emsg = got_int = false;
catch_exception((except_T *)cstack->cs_exception[idx]);
/* It's mandatory that the current exception is stored in the cstack
* so that it can be discarded at the next ":catch", ":finally", or
@@ -1428,7 +1403,7 @@ void ex_catch(exarg_T *eap)
}
// Discarding current_exceptions happens based on what is stored in
// cstack->cs_exception, *all* calls to discard_current_exception() are
// (and must be) guarded by did_throw which was already unset above.
// (and must be) guarded by current_exception check.
current_exception = NULL;
} else {
/*
@@ -1488,7 +1463,7 @@ void ex_finally(exarg_T *eap)
* interrupt or throw) or for a ":finally" without ":try" or a multiple
* ":finally". After every other error (did_emsg or the conditional
* errors detected above) or after an interrupt (got_int) or an
* exception (did_throw), the finally clause must be executed.
* exception (current_exception), the finally clause must be executed.
*/
skip = !(cstack->cs_flags[cstack->cs_idx] & CSF_TRUE);
@@ -1515,30 +1490,31 @@ void ex_finally(exarg_T *eap)
cleanup_conditionals(cstack, CSF_TRY, FALSE);
/*
* Make did_emsg, got_int, did_throw pending. If set, they overrule
* a pending ":continue", ":break", ":return", or ":finish". Then
* we have particularly to discard a pending return value (as done
* Make did_emsg, got_int, current_exception pending. If set, they
* overrule a pending ":continue", ":break", ":return", or ":finish".
* Then we have particularly to discard a pending return value (as done
* by the call to cleanup_conditionals() above when did_emsg or
* got_int is set). The pending values are restored by the
* ":endtry", except if there is a new error, interrupt, exception,
* ":continue", ":break", ":return", or ":finish" in the following
* finally clause. A missing ":endwhile", ":endfor" or ":endif"
* detected here is treated as if did_emsg and did_throw had
* detected here is treated as if did_emsg and current_exception had
* already been set, respectively in case that the error is not
* converted to an exception, did_throw had already been unset.
* converted to an exception, current_exception had already been unset.
* We must not set did_emsg here since that would suppress the
* error message.
*/
if (pending == CSTP_ERROR || did_emsg || got_int || did_throw) {
if (pending == CSTP_ERROR || did_emsg || got_int || current_exception) {
if (cstack->cs_pending[cstack->cs_idx] == CSTP_RETURN) {
report_discard_pending(CSTP_RETURN,
cstack->cs_rettv[cstack->cs_idx]);
discard_pending_return(cstack->cs_rettv[cstack->cs_idx]);
}
if (pending == CSTP_ERROR && !did_emsg)
pending |= (THROW_ON_ERROR) ? CSTP_THROW : 0;
else
pending |= did_throw ? CSTP_THROW : 0;
if (pending == CSTP_ERROR && !did_emsg) {
pending |= (THROW_ON_ERROR ? CSTP_THROW : 0);
} else {
pending |= (current_exception ? CSTP_THROW : 0);
}
pending |= did_emsg ? CSTP_ERROR : 0;
pending |= got_int ? CSTP_INTERRUPT : 0;
assert(pending >= CHAR_MIN && pending <= CHAR_MAX);
@@ -1551,14 +1527,15 @@ void ex_finally(exarg_T *eap)
* exception. When emsg() is called for a missing ":endif" or
* a missing ":endwhile"/":endfor" detected here, the
* exception will be discarded. */
if (did_throw && cstack->cs_exception[cstack->cs_idx]
!= current_exception)
if (current_exception
&& cstack->cs_exception[cstack->cs_idx] != current_exception) {
internal_error("ex_finally()");
}
}
/*
* Set CSL_HAD_FINA, so do_cmdline() will reset did_emsg,
* got_int, and did_throw and make the finally clause active.
* got_int, and current_exception and make the finally clause active.
* This will happen after emsg() has been called for a missing
* ":endif" or a missing ":endwhile"/":endfor" detected here, so
* that the following finally clause will be executed even then.
@@ -1593,7 +1570,7 @@ void ex_endtry(exarg_T *eap)
// made inactive by a ":continue", ":break", ":return", or ":finish" in
// the finally clause. The latter case need not be tested since then
// anything pending has already been discarded.
skip = (did_emsg || got_int || did_throw
skip = (did_emsg || got_int || current_exception
|| !(cstack->cs_flags[cstack->cs_idx] & CSF_TRUE));
if (!(cstack->cs_flags[cstack->cs_idx] & CSF_TRY)) {
@@ -1610,12 +1587,13 @@ void ex_endtry(exarg_T *eap)
/*
* If an exception is being thrown, discard it to prevent it from
* being rethrown at the end of this function. It would be
* discarded by the error message, anyway. Resets did_throw.
* discarded by the error message, anyway. Resets current_exception.
* This does not affect the script termination due to the error
* since "trylevel" is decremented after emsg() has been called.
*/
if (did_throw)
if (current_exception) {
discard_current_exception();
}
} else {
idx = cstack->cs_idx;
@@ -1625,9 +1603,11 @@ void ex_endtry(exarg_T *eap)
* a finally clause, we need to rethrow it after closing the try
* conditional.
*/
if (did_throw && (cstack->cs_flags[idx] & CSF_TRUE)
&& !(cstack->cs_flags[idx] & CSF_FINALLY))
rethrow = TRUE;
if (current_exception
&& (cstack->cs_flags[idx] & CSF_TRUE)
&& !(cstack->cs_flags[idx] & CSF_FINALLY)) {
rethrow = true;
}
}
/* If there was no finally clause, show the user when debugging or
@@ -1648,11 +1628,12 @@ void ex_endtry(exarg_T *eap)
if (got_int) {
skip = TRUE;
(void)do_intthrow(cstack);
/* The do_intthrow() call may have reset did_throw or
* cstack->cs_pending[idx].*/
rethrow = FALSE;
if (did_throw && !(cstack->cs_flags[idx] & CSF_FINALLY))
rethrow = TRUE;
// The do_intthrow() call may have reset current_exception or
// cstack->cs_pending[idx].
rethrow = false;
if (current_exception && !(cstack->cs_flags[idx] & CSF_FINALLY)) {
rethrow = true;
}
}
}
@@ -1714,26 +1695,30 @@ void ex_endtry(exarg_T *eap)
do_finish(eap, FALSE);
break;
/* When the finally clause was entered due to an error,
* interrupt or throw (as opposed to a ":continue", ":break",
* ":return", or ":finish"), restore the pending values of
* did_emsg, got_int, and did_throw. This is skipped, if there
* was a new error, interrupt, throw, ":continue", ":break",
* ":return", or ":finish". in the finally clause. */
// When the finally clause was entered due to an error,
// interrupt or throw (as opposed to a ":continue", ":break",
// ":return", or ":finish"), restore the pending values of
// did_emsg, got_int, and current_exception. This is skipped, if there
// was a new error, interrupt, throw, ":continue", ":break",
// ":return", or ":finish". in the finally clause.
default:
if (pending & CSTP_ERROR)
did_emsg = TRUE;
if (pending & CSTP_INTERRUPT)
got_int = TRUE;
if (pending & CSTP_THROW)
rethrow = TRUE;
if (pending & CSTP_ERROR) {
did_emsg = true;
}
if (pending & CSTP_INTERRUPT) {
got_int = true;
}
if (pending & CSTP_THROW) {
rethrow = true;
}
break;
}
}
if (rethrow)
/* Rethrow the current exception (within this cstack). */
if (rethrow) {
// Rethrow the current exception (within this cstack).
do_throw(cstack);
}
}
}
@@ -1763,33 +1748,33 @@ void enter_cleanup(cleanup_T *csp)
int pending = CSTP_NONE;
/*
* Postpone did_emsg, got_int, did_throw. The pending values will be
* Postpone did_emsg, got_int, current_exception. The pending values will be
* restored by leave_cleanup() except if there was an aborting error,
* interrupt, or uncaught exception after this function ends.
*/
if (did_emsg || got_int || did_throw || need_rethrow) {
csp->pending = (did_emsg ? CSTP_ERROR : 0)
| (got_int ? CSTP_INTERRUPT : 0)
| (did_throw ? CSTP_THROW : 0)
| (need_rethrow ? CSTP_THROW : 0);
if (did_emsg || got_int || current_exception || need_rethrow) {
csp->pending = (did_emsg ? CSTP_ERROR : 0)
| (got_int ? CSTP_INTERRUPT : 0)
| (current_exception ? CSTP_THROW : 0)
| (need_rethrow ? CSTP_THROW : 0);
/* If we are currently throwing an exception (did_throw), save it as
* well. On an error not yet converted to an exception, update
* "force_abort" and reset "cause_abort" (as do_errthrow() would do).
* This is needed for the do_cmdline() call that is going to be made
* for autocommand execution. We need not save *msg_list because
* there is an extra instance for every call of do_cmdline(), anyway.
/* If we are currently throwing an exception, save it as well. On an error
* not yet converted to an exception, update "force_abort" and reset
* "cause_abort" (as do_errthrow() would do). This is needed for the
* do_cmdline() call that is going to be made for autocommand execution. We
* need not save *msg_list because there is an extra instance for every call
* of do_cmdline(), anyway.
*/
if (did_throw || need_rethrow)
if (current_exception || need_rethrow) {
csp->exception = current_exception;
else {
} else {
csp->exception = NULL;
if (did_emsg) {
force_abort |= cause_abort;
cause_abort = FALSE;
}
}
did_emsg = got_int = did_throw = need_rethrow = false;
did_emsg = got_int = need_rethrow = false;
current_exception = NULL;
/* Report if required by the 'verbose' option or when debugging. */
@@ -1862,19 +1847,20 @@ void leave_cleanup(cleanup_T *csp)
force_abort = FALSE;
}
/*
* Restore the pending values of did_emsg, got_int, and did_throw.
*/
if (pending & CSTP_ERROR)
did_emsg = TRUE;
if (pending & CSTP_INTERRUPT)
got_int = TRUE;
if (pending & CSTP_THROW)
need_rethrow = TRUE; /* did_throw will be set by do_one_cmd() */
// Restore the pending values of did_emsg, got_int, and current_exception.
if (pending & CSTP_ERROR) {
did_emsg = true;
}
if (pending & CSTP_INTERRUPT) {
got_int = true;
}
if (pending & CSTP_THROW) {
need_rethrow = true; // current_exception will be set by do_one_cmd()
}
/* Report if required by the 'verbose' option or when debugging. */
report_resume_pending(pending,
(pending & CSTP_THROW) ? (void *)current_exception : NULL);
// Report if required by the 'verbose' option or when debugging.
report_resume_pending(
pending, ((pending & CSTP_THROW) ? (void *)current_exception : NULL));
}
}