mirror of
https://github.com/neovim/neovim.git
synced 2024-12-21 19:55:04 -07:00
*: Replace did_throw checks with current_exception checks
Removes obsolete did_throw after that.
This commit is contained in:
parent
79b4b6fc86
commit
201a4ef11c
@ -56,7 +56,6 @@ void try_enter(TryState *const tstate)
|
||||
.private_msg_list = NULL,
|
||||
.trylevel = trylevel,
|
||||
.got_int = got_int,
|
||||
.did_throw = did_throw,
|
||||
.need_rethrow = need_rethrow,
|
||||
.did_emsg = did_emsg,
|
||||
};
|
||||
@ -64,7 +63,6 @@ void try_enter(TryState *const tstate)
|
||||
current_exception = NULL;
|
||||
trylevel = 1;
|
||||
got_int = false;
|
||||
did_throw = false;
|
||||
need_rethrow = false;
|
||||
did_emsg = false;
|
||||
}
|
||||
@ -85,7 +83,6 @@ bool try_leave(const TryState *const tstate, Error *const err)
|
||||
assert(trylevel == 0);
|
||||
assert(!need_rethrow);
|
||||
assert(!got_int);
|
||||
assert(!did_throw);
|
||||
assert(!did_emsg);
|
||||
assert(msg_list == &tstate->private_msg_list);
|
||||
assert(*msg_list == NULL);
|
||||
@ -94,7 +91,6 @@ bool try_leave(const TryState *const tstate, Error *const err)
|
||||
current_exception = tstate->current_exception;
|
||||
trylevel = tstate->trylevel;
|
||||
got_int = tstate->got_int;
|
||||
did_throw = tstate->did_throw;
|
||||
need_rethrow = tstate->need_rethrow;
|
||||
did_emsg = tstate->did_emsg;
|
||||
return ret;
|
||||
@ -130,7 +126,7 @@ bool try_end(Error *err)
|
||||
did_emsg = false;
|
||||
|
||||
if (got_int) {
|
||||
if (did_throw) {
|
||||
if (current_exception) {
|
||||
// If we got an interrupt, discard the current exception
|
||||
discard_current_exception();
|
||||
}
|
||||
@ -149,7 +145,7 @@ bool try_end(Error *err)
|
||||
if (should_free) {
|
||||
xfree(msg);
|
||||
}
|
||||
} else if (did_throw) {
|
||||
} else if (current_exception) {
|
||||
api_set_error(err, kErrorTypeException, "%s", current_exception->value);
|
||||
discard_current_exception();
|
||||
}
|
||||
|
@ -93,7 +93,6 @@ typedef struct {
|
||||
const struct msglist *const *msg_list;
|
||||
int trylevel;
|
||||
int got_int;
|
||||
int did_throw;
|
||||
int need_rethrow;
|
||||
int did_emsg;
|
||||
} TryState;
|
||||
|
@ -133,7 +133,6 @@ struct dbg_stuff {
|
||||
char_u *vv_throwpoint;
|
||||
int did_emsg;
|
||||
int got_int;
|
||||
int did_throw;
|
||||
int need_rethrow;
|
||||
int check_cstack;
|
||||
except_T *current_exception;
|
||||
@ -165,12 +164,11 @@ static void save_dbg_stuff(struct dbg_stuff *dsp)
|
||||
dsp->vv_exception = v_exception(NULL);
|
||||
dsp->vv_throwpoint = v_throwpoint(NULL);
|
||||
|
||||
/* Necessary for debugging an inactive ":catch", ":finally", ":endtry" */
|
||||
dsp->did_emsg = did_emsg; did_emsg = FALSE;
|
||||
dsp->got_int = got_int; got_int = FALSE;
|
||||
dsp->did_throw = did_throw; did_throw = FALSE;
|
||||
dsp->need_rethrow = need_rethrow; need_rethrow = FALSE;
|
||||
dsp->check_cstack = check_cstack; check_cstack = FALSE;
|
||||
// Necessary for debugging an inactive ":catch", ":finally", ":endtry".
|
||||
dsp->did_emsg = did_emsg; did_emsg = false;
|
||||
dsp->got_int = got_int; got_int = false;
|
||||
dsp->need_rethrow = need_rethrow; need_rethrow = false;
|
||||
dsp->check_cstack = check_cstack; check_cstack = false;
|
||||
dsp->current_exception = current_exception; current_exception = NULL;
|
||||
}
|
||||
|
||||
@ -184,7 +182,6 @@ static void restore_dbg_stuff(struct dbg_stuff *dsp)
|
||||
(void)v_throwpoint(dsp->vv_throwpoint);
|
||||
did_emsg = dsp->did_emsg;
|
||||
got_int = dsp->got_int;
|
||||
did_throw = dsp->did_throw;
|
||||
need_rethrow = dsp->need_rethrow;
|
||||
check_cstack = dsp->check_cstack;
|
||||
current_exception = dsp->current_exception;
|
||||
@ -400,10 +397,6 @@ int do_cmdline(char_u *cmdline, LineGetter fgetline,
|
||||
|
||||
initial_trylevel = trylevel;
|
||||
|
||||
/*
|
||||
* "did_throw" will be set to TRUE when an exception is being thrown.
|
||||
*/
|
||||
did_throw = false;
|
||||
current_exception = NULL;
|
||||
// "did_emsg" will be set to TRUE when emsg() is used, in which case we
|
||||
// cancel the whole command line, and any if/endif or loop.
|
||||
@ -658,7 +651,7 @@ int do_cmdline(char_u *cmdline, LineGetter fgetline,
|
||||
* not to use a cs_line[] from an entry that isn't a ":while"
|
||||
* or ":for": It would make "current_line" invalid and can
|
||||
* cause a crash. */
|
||||
if (!did_emsg && !got_int && !did_throw
|
||||
if (!did_emsg && !got_int && !current_exception
|
||||
&& cstack.cs_idx >= 0
|
||||
&& (cstack.cs_flags[cstack.cs_idx]
|
||||
& (CSF_WHILE | CSF_FOR))
|
||||
@ -706,7 +699,7 @@ int do_cmdline(char_u *cmdline, LineGetter fgetline,
|
||||
}
|
||||
|
||||
/*
|
||||
* A ":finally" makes did_emsg, got_int, and did_throw pending for
|
||||
* A ":finally" makes did_emsg, got_int and current_exception pending for
|
||||
* being restored at the ":endtry". Reset them here and set the
|
||||
* ACTIVE and FINALLY flags, so that the finally clause gets executed.
|
||||
* This includes the case where a missing ":endif", ":endwhile" or
|
||||
@ -716,8 +709,8 @@ int do_cmdline(char_u *cmdline, LineGetter fgetline,
|
||||
cstack.cs_lflags &= ~CSL_HAD_FINA;
|
||||
report_make_pending((cstack.cs_pending[cstack.cs_idx]
|
||||
& (CSTP_ERROR | CSTP_INTERRUPT | CSTP_THROW)),
|
||||
(did_throw ? (void *)current_exception : NULL));
|
||||
did_emsg = got_int = did_throw = false;
|
||||
current_exception);
|
||||
did_emsg = got_int = false;
|
||||
current_exception = NULL;
|
||||
cstack.cs_flags[cstack.cs_idx] |= CSF_ACTIVE | CSF_FINALLY;
|
||||
}
|
||||
@ -726,15 +719,14 @@ int do_cmdline(char_u *cmdline, LineGetter fgetline,
|
||||
* within this loop. */
|
||||
trylevel = initial_trylevel + cstack.cs_trylevel;
|
||||
|
||||
/*
|
||||
* If the outermost try conditional (across function calls and sourced
|
||||
* files) is aborted because of an error, an interrupt, or an uncaught
|
||||
* exception, cancel everything. If it is left normally, reset
|
||||
* force_abort to get the non-EH compatible abortion behavior for
|
||||
* the rest of the script.
|
||||
*/
|
||||
if (trylevel == 0 && !did_emsg && !got_int && !did_throw)
|
||||
force_abort = FALSE;
|
||||
// If the outermost try conditional (across function calls and sourced
|
||||
// files) is aborted because of an error, an interrupt, or an uncaught
|
||||
// exception, cancel everything. If it is left normally, reset
|
||||
// force_abort to get the non-EH compatible abortion behavior for
|
||||
// the rest of the script.
|
||||
if (trylevel == 0 && !did_emsg && !got_int && !current_exception) {
|
||||
force_abort = false;
|
||||
}
|
||||
|
||||
/* Convert an interrupt to an exception if appropriate. */
|
||||
(void)do_intthrow(&cstack);
|
||||
@ -749,11 +741,8 @@ int do_cmdline(char_u *cmdline, LineGetter fgetline,
|
||||
* - there is a command after '|', inside a :if, :while, :for or :try, or
|
||||
* looping for ":source" command or function call.
|
||||
*/
|
||||
while (!((got_int
|
||||
|| (did_emsg && force_abort) || did_throw
|
||||
)
|
||||
&& cstack.cs_trylevel == 0
|
||||
)
|
||||
while (!((got_int || (did_emsg && force_abort) || current_exception)
|
||||
&& cstack.cs_trylevel == 0)
|
||||
&& !(did_emsg
|
||||
/* Keep going when inside try/catch, so that the error can be
|
||||
* deal with, except when it is a syntax error, it may cause
|
||||
@ -775,7 +764,7 @@ int do_cmdline(char_u *cmdline, LineGetter fgetline,
|
||||
* If a sourced file or executed function ran to its end, report the
|
||||
* unclosed conditional.
|
||||
*/
|
||||
if (!got_int && !did_throw
|
||||
if (!got_int && !current_exception
|
||||
&& ((getline_equal(fgetline, cookie, getsourceline)
|
||||
&& !source_finished(fgetline, cookie))
|
||||
|| (getline_equal(fgetline, cookie, get_func_line)
|
||||
@ -815,17 +804,16 @@ int do_cmdline(char_u *cmdline, LineGetter fgetline,
|
||||
? (char_u *)"endfunction" : (char_u *)NULL);
|
||||
|
||||
if (trylevel == 0) {
|
||||
/*
|
||||
* When an exception is being thrown out of the outermost try
|
||||
* conditional, discard the uncaught exception, disable the conversion
|
||||
* of interrupts or errors to exceptions, and ensure that no more
|
||||
* commands are executed.
|
||||
*/
|
||||
if (did_throw) {
|
||||
void *p = NULL;
|
||||
char_u *saved_sourcing_name;
|
||||
// When an exception is being thrown out of the outermost try
|
||||
// conditional, discard the uncaught exception, disable the conversion
|
||||
// of interrupts or errors to exceptions, and ensure that no more
|
||||
// commands are executed.
|
||||
if (current_exception) {
|
||||
void *p = NULL;
|
||||
char_u *saved_sourcing_name;
|
||||
int saved_sourcing_lnum;
|
||||
struct msglist *messages = NULL, *next;
|
||||
struct msglist *messages = NULL;
|
||||
struct msglist *next;
|
||||
|
||||
/*
|
||||
* If the uncaught exception is a user exception, report it as an
|
||||
@ -885,22 +873,22 @@ int do_cmdline(char_u *cmdline, LineGetter fgetline,
|
||||
suppress_errthrow = TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* The current cstack will be freed when do_cmdline() returns. An uncaught
|
||||
* exception will have to be rethrown in the previous cstack. If a function
|
||||
* has just returned or a script file was just finished and the previous
|
||||
* cstack belongs to the same function or, respectively, script file, it
|
||||
* will have to be checked for finally clauses to be executed due to the
|
||||
* ":return" or ":finish". This is done in do_one_cmd().
|
||||
*/
|
||||
if (did_throw)
|
||||
need_rethrow = TRUE;
|
||||
// The current cstack will be freed when do_cmdline() returns. An uncaught
|
||||
// exception will have to be rethrown in the previous cstack. If a function
|
||||
// has just returned or a script file was just finished and the previous
|
||||
// cstack belongs to the same function or, respectively, script file, it
|
||||
// will have to be checked for finally clauses to be executed due to the
|
||||
// ":return" or ":finish". This is done in do_one_cmd().
|
||||
if (current_exception) {
|
||||
need_rethrow = true;
|
||||
}
|
||||
if ((getline_equal(fgetline, cookie, getsourceline)
|
||||
&& ex_nesting_level > source_level(real_cookie))
|
||||
|| (getline_equal(fgetline, cookie, get_func_line)
|
||||
&& ex_nesting_level > func_level(real_cookie) + 1)) {
|
||||
if (!did_throw)
|
||||
check_cstack = TRUE;
|
||||
if (!current_exception) {
|
||||
check_cstack = true;
|
||||
}
|
||||
} else {
|
||||
/* When leaving a function, reduce nesting level. */
|
||||
if (getline_equal(fgetline, cookie, get_func_line))
|
||||
@ -1480,10 +1468,11 @@ static char_u * do_one_cmd(char_u **cmdlinep,
|
||||
}
|
||||
char_u *after_modifier = ea.cmd;
|
||||
|
||||
ea.skip = did_emsg || got_int || did_throw || (cstack->cs_idx >= 0
|
||||
&& !(cstack->cs_flags[cstack->
|
||||
cs_idx]
|
||||
& CSF_ACTIVE));
|
||||
ea.skip = (did_emsg
|
||||
|| got_int
|
||||
|| current_exception
|
||||
|| (cstack->cs_idx >= 0
|
||||
&& !(cstack->cs_flags[cstack->cs_idx] & CSF_ACTIVE)));
|
||||
|
||||
/* Count this line for profiling if ea.skip is FALSE. */
|
||||
if (do_profiling == PROF_YES && !ea.skip) {
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -317,17 +317,10 @@ EXTERN int do_profiling INIT(= PROF_NONE); /* PROF_ values */
|
||||
/*
|
||||
* The exception currently being thrown. Used to pass an exception to
|
||||
* a different cstack. Also used for discarding an exception before it is
|
||||
* caught or made pending. Only valid when did_throw is TRUE.
|
||||
* caught or made pending.
|
||||
*/
|
||||
EXTERN except_T *current_exception;
|
||||
|
||||
/*
|
||||
* did_throw: An exception is being thrown. Reset when the exception is caught
|
||||
* or as long as it is pending in a finally clause.
|
||||
*/
|
||||
// FIXME: Replace did_throw checks with current_exception checks.
|
||||
EXTERN int did_throw INIT(= false);
|
||||
|
||||
/*
|
||||
* need_rethrow: set to TRUE when a throw that cannot be handled in do_cmdline()
|
||||
* must be propagated to the cstack of the previously called do_cmdline().
|
||||
|
Loading…
Reference in New Issue
Block a user