aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/ex_eval.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/ex_eval.c')
-rw-r--r--src/nvim/ex_eval.c401
1 files changed, 174 insertions, 227 deletions
diff --git a/src/nvim/ex_eval.c b/src/nvim/ex_eval.c
index b1c59a607c..46b9528546 100644
--- a/src/nvim/ex_eval.c
+++ b/src/nvim/ex_eval.c
@@ -75,7 +75,10 @@
|| (cstack->cs_idx > 0 \
&& !(cstack->cs_flags[cstack->cs_idx - 1] & CSF_ACTIVE)))
-#define discard_pending_return(p) tv_free((typval_T *)(p))
+static void discard_pending_return(typval_T *p)
+{
+ tv_free(p);
+}
/*
* When several errors appear in a row, setting "force_abort" is delayed until
@@ -88,27 +91,26 @@
*/
static int cause_abort = FALSE;
-// Return true when immediately aborting on error, or when an interrupt
-// occurred or an exception was thrown but not caught. Use for ":{range}call"
-// to check whether an aborted function that does not handle a range itself
-// should be called again for the next line in the range. Also used for
-// cancelling expression evaluation after a function call caused an immediate
-// abort. Note that the first emsg() call temporarily resets "force_abort"
-// until the throw point for error messages has been reached. That is, during
-// cancellation of an expression evaluation after an aborting function call or
-// due to a parsing error, aborting() always returns the same value.
-// "got_int" is also set by calling interrupt().
+/// @return true when immediately aborting on error, or when an interrupt
+/// occurred or an exception was thrown but not caught.
+///
+/// Use for ":{range}call" to check whether an aborted function that does not
+/// handle a range itself should be called again for the next line in the range.
+/// Also used for cancelling expression evaluation after a function call caused
+/// an immediate abort. Note that the first emsg() call temporarily resets
+/// "force_abort" until the throw point for error messages has been reached.
+/// That is, during cancellation of an expression evaluation after an aborting
+/// function call or due to a parsing error, aborting() always returns the same
+/// value. "got_int" is also set by calling interrupt().
int aborting(void)
{
return (did_emsg && force_abort) || got_int || current_exception;
}
-/*
- * The value of "force_abort" is temporarily reset by the first emsg() call
- * during an expression evaluation, and "cause_abort" is used instead. It might
- * be necessary to restore "force_abort" even before the throw point for the
- * error message has been reached. update_force_abort() should be called then.
- */
+/// The value of "force_abort" is temporarily reset by the first emsg() call
+/// during an expression evaluation, and "cause_abort" is used instead. It might
+/// be necessary to restore "force_abort" even before the throw point for the
+/// error message has been reached. update_force_abort() should be called then.
void update_force_abort(void)
{
if (cause_abort) {
@@ -116,38 +118,37 @@ void update_force_abort(void)
}
}
-/*
- * Return TRUE if a command with a subcommand resulting in "retcode" should
- * abort the script processing. Can be used to suppress an autocommand after
- * execution of a failing subcommand as long as the error message has not been
- * displayed and actually caused the abortion.
- */
+/// @return TRUE if a command with a subcommand resulting in "retcode" should
+/// abort the script processing. Can be used to suppress an autocommand after
+/// execution of a failing subcommand as long as the error message has not been
+/// displayed and actually caused the abortion.
int should_abort(int retcode)
{
return (retcode == FAIL && trylevel != 0 && !emsg_silent) || aborting();
}
-/*
- * Return TRUE if a function with the "abort" flag should not be considered
- * ended on an error. This means that parsing commands is continued in order
- * to find finally clauses to be executed, and that some errors in skipped
- * commands are still reported.
- */
+/// @return TRUE if a function with the "abort" flag should not be considered
+/// ended on an error. This means that parsing commands is continued in order
+/// to find finally clauses to be executed, and that some errors in skipped
+/// commands are still reported.
int aborted_in_try(void)
+ FUNC_ATTR_PURE
{
// This function is only called after an error. In this case, "force_abort"
// determines whether searching for finally clauses is necessary.
return force_abort;
}
-// cause_errthrow(): Cause a throw of an error exception if appropriate.
-// Return true if the error message should not be displayed by emsg().
-// Sets "ignore", if the emsg() call should be ignored completely.
-//
-// When several messages appear in the same command, the first is usually the
-// most specific one and used as the exception value. The "severe" flag can be
-// set to true, if a later but severer message should be used instead.
-bool cause_errthrow(const char_u *mesg, bool severe, bool *ignore)
+/// cause_errthrow(): Cause a throw of an error exception if appropriate.
+///
+/// @return true if the error message should not be displayed by emsg().
+///
+/// Sets "ignore", if the emsg() call should be ignored completely.
+///
+/// When several messages appear in the same command, the first is usually the
+/// most specific one and used as the exception value. The "severe" flag can be
+/// set to true, if a later but severer message should be used instead.
+bool cause_errthrow(const char *mesg, bool severe, bool *ignore)
FUNC_ATTR_NONNULL_ALL
{
struct msglist *elem;
@@ -196,7 +197,7 @@ bool cause_errthrow(const char_u *mesg, bool severe, bool *ignore)
* interrupt exception is catchable by the innermost try conditional and
* not replaced by an interrupt message error exception.
*/
- if (mesg == (char_u *)_(e_interr)) {
+ if (mesg == _(e_interr)) {
*ignore = true;
return true;
}
@@ -254,7 +255,7 @@ bool cause_errthrow(const char_u *mesg, bool severe, bool *ignore)
}
elem = xmalloc(sizeof(struct msglist));
- elem->msg = (char *)vim_strsave(mesg);
+ elem->msg = xstrdup(mesg);
elem->next = NULL;
elem->throw_msg = NULL;
*plist = elem;
@@ -279,9 +280,7 @@ bool cause_errthrow(const char_u *mesg, bool severe, bool *ignore)
}
}
-/*
- * Free a "msg_list" and the messages it contains.
- */
+/// Free a "msg_list" and the messages it contains.
static void free_msglist(struct msglist *l)
{
struct msglist *messages, *next;
@@ -295,22 +294,18 @@ static void free_msglist(struct msglist *l)
}
}
-/*
- * Free global "*msg_list" and the messages it contains, then set "*msg_list"
- * to NULL.
- */
+/// Free global "*msg_list" and the messages it contains, then set "*msg_list"
+/// to NULL.
void free_global_msglist(void)
{
free_msglist(*msg_list);
*msg_list = NULL;
}
-/*
- * Throw the message specified in the call to cause_errthrow() above as an
- * error exception. If cstack is NULL, postpone the throw until do_cmdline()
- * has returned (see do_one_cmd()).
- */
-void do_errthrow(cstack_T *cstack, char_u *cmdname)
+/// Throw the message specified in the call to cause_errthrow() above as an
+/// error exception. If cstack is NULL, postpone the throw until do_cmdline()
+/// has returned (see do_one_cmd()).
+void do_errthrow(cstack_T *cstack, char *cmdname)
{
/*
* Ensure that all commands in nested function calls and sourced files
@@ -339,11 +334,11 @@ void do_errthrow(cstack_T *cstack, char_u *cmdname)
*msg_list = NULL;
}
-/*
- * do_intthrow(): Replace the current exception by an interrupt or interrupt
- * exception if appropriate. Return TRUE if the current exception is discarded,
- * FALSE otherwise.
- */
+/// do_intthrow(): Replace the current exception by an interrupt or interrupt
+/// exception if appropriate.
+///
+/// @return TRUE if the current exception is discarded or,
+/// FALSE otherwise.
int do_intthrow(cstack_T *cstack)
{
// If no interrupt occurred or no try conditional is active and no exception
@@ -386,8 +381,8 @@ int do_intthrow(cstack_T *cstack)
return true;
}
-// Get an exception message that is to be stored in current_exception->value.
-char *get_exception_string(void *value, except_type_T type, char_u *cmdname, int *should_free)
+/// Get an exception message that is to be stored in current_exception->value.
+char *get_exception_string(void *value, except_type_T type, char *cmdname, int *should_free)
{
char *ret, *mesg;
char *p, *val;
@@ -397,12 +392,12 @@ char *get_exception_string(void *value, except_type_T type, char_u *cmdname, int
mesg = ((struct msglist *)value)->throw_msg;
if (cmdname != NULL && *cmdname != NUL) {
size_t cmdlen = STRLEN(cmdname);
- ret = (char *)vim_strnsave((char_u *)"Vim(", 4 + cmdlen + 2 + STRLEN(mesg));
+ ret = xstrnsave("Vim(", 4 + cmdlen + 2 + STRLEN(mesg));
STRCPY(&ret[4], cmdname);
STRCPY(&ret[4 + cmdlen], "):");
val = ret + 4 + cmdlen + 2;
} else {
- ret = (char *)vim_strnsave((char_u *)"Vim:", 4 + STRLEN(mesg));
+ ret = xstrnsave("Vim:", 4 + STRLEN(mesg));
val = ret + 4;
}
@@ -422,7 +417,7 @@ char *get_exception_string(void *value, except_type_T type, char_u *cmdname, int
STRCAT(val, mesg); // 'E123' missing or at beginning
} else {
// '"filename" E123: message text'
- if (mesg[0] != '"' || p-2 < &mesg[1]
+ if (mesg[0] != '"' || p - 2 < &mesg[1]
|| p[-2] != '"' || p[-1] != ' ') {
// "E123:" is part of the file name.
continue;
@@ -430,7 +425,7 @@ char *get_exception_string(void *value, except_type_T type, char_u *cmdname, int
STRCAT(val, p);
p[-2] = NUL;
- sprintf((char *)(val + STRLEN(p)), " (%s)", &mesg[1]);
+ snprintf(val + STRLEN(p), strlen(" (%s)"), " (%s)", &mesg[1]);
p[-2] = '"';
}
break;
@@ -444,12 +439,13 @@ char *get_exception_string(void *value, except_type_T type, char_u *cmdname, int
return ret;
}
-
-// Throw a new exception. Return FAIL when out of memory or it was tried to
-// throw an illegal user exception. "value" is the exception string for a
-// user or interrupt exception, or points to a message list in case of an
-// error exception.
-static int throw_exception(void *value, except_type_T type, char_u *cmdname)
+/// Throw a new exception. "value" is the exception string for a
+/// user or interrupt exception, or points to a message list in case of an
+/// error exception.
+///
+/// @return FAIL when out of memory or it was tried to throw an illegal user
+/// exception.
+static int throw_exception(void *value, except_type_T type, char *cmdname)
{
except_T *excp;
int should_free;
@@ -482,8 +478,7 @@ static int throw_exception(void *value, except_type_T type, char_u *cmdname)
}
excp->type = type;
- excp->throw_name = vim_strsave(sourcing_name == NULL
- ? (char_u *)"" : sourcing_name);
+ excp->throw_name = xstrdup(sourcing_name == NULL ? "" : sourcing_name);
excp->throw_lnum = sourcing_lnum;
if (p_verbose >= 13 || debug_break_level > 0) {
@@ -524,13 +519,11 @@ fail:
return FAIL;
}
-/*
- * Discard an exception. "was_finished" is set when the exception has been
- * caught and the catch clause has been ended normally.
- */
+/// Discard an exception. "was_finished" is set when the exception has been
+/// caught and the catch clause has been ended normally.
static void discard_exception(except_T *excp, bool was_finished)
{
- char_u *saved_IObuff;
+ char *saved_IObuff;
if (current_exception == excp) {
current_exception = NULL;
@@ -543,7 +536,7 @@ static void discard_exception(except_T *excp, bool was_finished)
if (p_verbose >= 13 || debug_break_level > 0) {
int save_msg_silent = msg_silent;
- saved_IObuff = vim_strsave(IObuff);
+ saved_IObuff = (char *)vim_strsave(IObuff);
if (debug_break_level > 0) {
msg_silent = FALSE; // display messages
} else {
@@ -579,9 +572,7 @@ static void discard_exception(except_T *excp, bool was_finished)
xfree(excp);
}
-/*
- * Discard the exception currently being thrown.
- */
+/// Discard the exception currently being thrown.
void discard_current_exception(void)
{
if (current_exception != NULL) {
@@ -592,14 +583,12 @@ void discard_current_exception(void)
need_rethrow = false;
}
-/*
- * Put an exception on the caught stack.
- */
+/// Put an exception on the caught stack.
static void catch_exception(except_T *excp)
{
excp->caught = caught_stack;
caught_stack = excp;
- set_vim_var_string(VV_EXCEPTION, (char *)excp->value, -1);
+ set_vim_var_string(VV_EXCEPTION, excp->value, -1);
if (*excp->throw_name != NUL) {
if (excp->throw_lnum != 0) {
vim_snprintf((char *)IObuff, IOSIZE, _("%s, line %" PRId64),
@@ -640,9 +629,7 @@ static void catch_exception(except_T *excp)
}
}
-/*
- * Remove an exception from the caught stack.
- */
+/// Remove an exception from the caught stack.
static void finish_exception(except_T *excp)
{
if (excp != caught_stack) {
@@ -650,7 +637,7 @@ static void finish_exception(except_T *excp)
}
caught_stack = caught_stack->caught;
if (caught_stack != NULL) {
- set_vim_var_string(VV_EXCEPTION, (char *)caught_stack->value, -1);
+ set_vim_var_string(VV_EXCEPTION, caught_stack->value, -1);
if (*caught_stack->throw_name != NUL) {
if (caught_stack->throw_lnum != 0) {
vim_snprintf((char *)IObuff, IOSIZE,
@@ -682,13 +669,11 @@ static void finish_exception(except_T *excp)
#define RP_RESUME 1
#define RP_DISCARD 2
-/*
- * Report information about something pending in a finally clause if required by
- * the 'verbose' option or when debugging. "action" tells whether something is
- * made pending or something pending is resumed or discarded. "pending" tells
- * what is pending. "value" specifies the return value for a pending ":return"
- * or the exception value for a pending exception.
- */
+/// Report information about something pending in a finally clause if required by
+/// the 'verbose' option or when debugging. "action" tells whether something is
+/// made pending or something pending is resumed or discarded. "pending" tells
+/// what is pending. "value" specifies the return value for a pending ":return"
+/// or the exception value for a pending exception.
static void report_pending(int action, int pending, void *value)
{
char *mesg;
@@ -733,7 +718,7 @@ static void report_pending(int action, int pending, void *value)
vim_snprintf((char *)IObuff, IOSIZE,
mesg, _("Exception"));
mesg = (char *)concat_str(IObuff, (char_u *)": %s");
- s = (char *)((except_T *)value)->value;
+ s = ((except_T *)value)->value;
} else if ((pending & CSTP_ERROR) && (pending & CSTP_INTERRUPT)) {
s = _("Error and interrupt");
} else if (pending & CSTP_ERROR) {
@@ -764,10 +749,8 @@ static void report_pending(int action, int pending, void *value)
}
}
-/*
- * If something is made pending in a finally clause, report it if required by
- * the 'verbose' option or when debugging.
- */
+/// If something is made pending in a finally clause, report it if required by
+/// the 'verbose' option or when debugging.
void report_make_pending(int pending, void *value)
{
if (p_verbose >= 14 || debug_break_level > 0) {
@@ -781,10 +764,8 @@ void report_make_pending(int pending, void *value)
}
}
-/*
- * If something pending in a finally clause is resumed at the ":endtry", report
- * it if required by the 'verbose' option or when debugging.
- */
+/// If something pending in a finally clause is resumed at the ":endtry", report
+/// it if required by the 'verbose' option or when debugging.
void report_resume_pending(int pending, void *value)
{
if (p_verbose >= 14 || debug_break_level > 0) {
@@ -798,10 +779,8 @@ void report_resume_pending(int pending, void *value)
}
}
-/*
- * If something pending in a finally clause is discarded, report it if required
- * by the 'verbose' option or when debugging.
- */
+/// If something pending in a finally clause is discarded, report it if required
+/// by the 'verbose' option or when debugging.
void report_discard_pending(int pending, void *value)
{
if (p_verbose >= 14 || debug_break_level > 0) {
@@ -815,7 +794,7 @@ void report_discard_pending(int pending, void *value)
}
}
-// ":eval".
+/// Handle ":eval".
void ex_eval(exarg_T *eap)
{
typval_T tv;
@@ -825,9 +804,7 @@ void ex_eval(exarg_T *eap)
}
}
-/*
- * ":if".
- */
+/// Handle ":if".
void ex_if(exarg_T *eap)
{
int skip;
@@ -856,9 +833,7 @@ void ex_if(exarg_T *eap)
}
}
-/*
- * ":endif".
- */
+/// Handle ":endif".
void ex_endif(exarg_T *eap)
{
did_endif = true;
@@ -883,9 +858,7 @@ void ex_endif(exarg_T *eap)
}
}
-/*
- * ":else" and ":elseif".
- */
+/// Handle ":else" and ":elseif".
void ex_else(exarg_T *eap)
{
int result;
@@ -958,9 +931,7 @@ void ex_else(exarg_T *eap)
}
}
-/*
- * Handle ":while" and ":for".
- */
+/// Handle ":while" and ":for".
void ex_while(exarg_T *eap)
{
bool error;
@@ -1041,9 +1012,7 @@ void ex_while(exarg_T *eap)
}
}
-/*
- * ":continue"
- */
+/// Handle ":continue"
void ex_continue(exarg_T *eap)
{
int idx;
@@ -1075,9 +1044,7 @@ void ex_continue(exarg_T *eap)
}
}
-/*
- * ":break"
- */
+/// Handle ":break"
void ex_break(exarg_T *eap)
{
int idx;
@@ -1098,9 +1065,7 @@ void ex_break(exarg_T *eap)
}
}
-/*
- * ":endwhile" and ":endfor"
- */
+/// Handle ":endwhile" and ":endfor"
void ex_endwhile(exarg_T *eap)
{
cstack_T *const cstack = eap->cstack;
@@ -1120,7 +1085,7 @@ void ex_endwhile(exarg_T *eap)
if (cstack->cs_looplevel <= 0 || cstack->cs_idx < 0) {
eap->errmsg = err;
} else {
- fl = cstack->cs_flags[cstack->cs_idx];
+ fl = cstack->cs_flags[cstack->cs_idx];
if (!(fl & csf)) {
// If we are in a ":while" or ":for" but used the wrong endloop
// command, do not rewind to the next enclosing ":for"/":while".
@@ -1174,10 +1139,7 @@ void ex_endwhile(exarg_T *eap)
}
}
-
-/*
- * ":throw expr"
- */
+/// Handle ":throw expr"
void ex_throw(exarg_T *eap)
{
const char *arg = (const char *)eap->arg;
@@ -1202,11 +1164,9 @@ void ex_throw(exarg_T *eap)
}
}
-/*
- * Throw the current exception through the specified cstack. Common routine
- * for ":throw" (user exception) and error and interrupt exceptions. Also
- * used for rethrowing an uncaught exception.
- */
+/// Throw the current exception through the specified cstack. Common routine
+/// for ":throw" (user exception) and error and interrupt exceptions. Also
+/// used for rethrowing an uncaught exception.
void do_throw(cstack_T *cstack)
{
int idx;
@@ -1263,9 +1223,7 @@ void do_throw(cstack_T *cstack)
}
}
-/*
- * ":try"
- */
+/// Handle ":try"
void ex_try(exarg_T *eap)
{
int skip;
@@ -1315,22 +1273,20 @@ void ex_try(exarg_T *eap)
}
}
-/*
- * ":catch /{pattern}/" and ":catch"
- */
+/// Handle ":catch /{pattern}/" and ":catch"
void ex_catch(exarg_T *eap)
{
int idx = 0;
bool give_up = false;
bool skip = false;
bool caught = false;
- char_u *end;
- char_u save_char = 0;
- char_u *save_cpo;
+ char *end;
+ char save_char = 0;
+ char *save_cpo;
regmatch_T regmatch;
int prev_got_int;
cstack_T *const cstack = eap->cstack;
- char_u *pat;
+ char *pat;
if (cstack->cs_trylevel <= 0 || cstack->cs_idx < 0) {
eap->errmsg = N_("E603: :catch without :try");
@@ -1359,12 +1315,12 @@ void ex_catch(exarg_T *eap)
}
if (ends_excmd(*eap->arg)) { // no argument, catch all errors
- pat = (char_u *)".*";
+ pat = ".*";
end = NULL;
- eap->nextcmd = find_nextcmd(eap->arg);
+ eap->nextcmd = (char *)find_nextcmd((char_u *)eap->arg);
} else {
pat = eap->arg + 1;
- end = skip_regexp(pat, *eap->arg, TRUE, NULL);
+ end = (char *)skip_regexp((char_u *)pat, *eap->arg, true, NULL);
}
if (!give_up) {
@@ -1403,8 +1359,8 @@ void ex_catch(exarg_T *eap)
save_char = *end;
*end = NUL;
}
- save_cpo = p_cpo;
- p_cpo = (char_u *)"";
+ save_cpo = p_cpo;
+ p_cpo = "";
// Disable error messages, it will make current exception
// invalid
emsg_off++;
@@ -1467,13 +1423,11 @@ void ex_catch(exarg_T *eap)
}
if (end != NULL) {
- eap->nextcmd = find_nextcmd(end);
+ eap->nextcmd = (char *)find_nextcmd((char_u *)end);
}
}
-/*
- * ":finally"
- */
+/// Handle ":finally"
void ex_finally(exarg_T *eap)
{
int idx;
@@ -1595,14 +1549,12 @@ void ex_finally(exarg_T *eap)
}
}
-/*
- * ":endtry"
- */
+/// Handle ":endtry"
void ex_endtry(exarg_T *eap)
{
int idx;
bool rethrow = false;
- int pending = CSTP_NONE;
+ char pending = CSTP_NONE;
void *rettv = NULL;
cstack_T *const cstack = eap->cstack;
@@ -1620,10 +1572,11 @@ void ex_endtry(exarg_T *eap)
// the finally clause. The latter case need not be tested since then
// anything pending has already been discarded.
bool skip = did_emsg || got_int || current_exception
- || !(cstack->cs_flags[cstack->cs_idx] & CSF_TRUE);
+ || !(cstack->cs_flags[cstack->cs_idx] & CSF_TRUE);
if (!(cstack->cs_flags[cstack->cs_idx] & CSF_TRY)) {
eap->errmsg = get_end_emsg(cstack);
+
// Find the matching ":try" and report what's missing.
idx = cstack->cs_idx;
do {
@@ -1643,6 +1596,9 @@ void ex_endtry(exarg_T *eap)
if (current_exception) {
discard_current_exception();
}
+
+ // report eap->errmsg, also when there already was an error
+ did_emsg = false;
} else {
idx = cstack->cs_idx;
@@ -1713,8 +1669,10 @@ void ex_endtry(exarg_T *eap)
*/
(void)cleanup_conditionals(cstack, CSF_TRY | CSF_SILENT, TRUE);
- --cstack->cs_idx;
- --cstack->cs_trylevel;
+ if (cstack->cs_idx >= 0 && (cstack->cs_flags[cstack->cs_idx] & CSF_TRY)) {
+ cstack->cs_idx--;
+ }
+ cstack->cs_trylevel--;
if (!skip) {
report_resume_pending(pending,
@@ -1784,14 +1742,12 @@ void ex_endtry(exarg_T *eap)
* error/interrupt/exception state.
*/
-/*
- * This function works a bit like ex_finally() except that there was not
- * actually an extra try block around the part that failed and an error or
- * interrupt has not (yet) been converted to an exception. This function
- * saves the error/interrupt/ exception state and prepares for the call to
- * do_cmdline() that is going to be made for the cleanup autocommand
- * execution.
- */
+/// This function works a bit like ex_finally() except that there was not
+/// actually an extra try block around the part that failed and an error or
+/// interrupt has not (yet) been converted to an exception. This function
+/// saves the error/interrupt/ exception state and prepares for the call to
+/// do_cmdline() that is going to be made for the cleanup autocommand
+/// execution.
void enter_cleanup(cleanup_T *csp)
{
int pending = CSTP_NONE;
@@ -1834,21 +1790,19 @@ void enter_cleanup(cleanup_T *csp)
}
}
-/*
- * See comment above enter_cleanup() for how this function is used.
- *
- * This function is a bit like ex_endtry() except that there was not actually
- * an extra try block around the part that failed and an error or interrupt
- * had not (yet) been converted to an exception when the cleanup autocommand
- * sequence was invoked.
- *
- * This function has to be called with the address of the cleanup_T structure
- * filled by enter_cleanup() as an argument; it restores the error/interrupt/
- * exception state saved by that function - except there was an aborting
- * error, an interrupt or an uncaught exception during execution of the
- * cleanup autocommands. In the latter case, the saved error/interrupt/
- * exception state is discarded.
- */
+/// This function is a bit like ex_endtry() except that there was not actually
+/// an extra try block around the part that failed and an error or interrupt
+/// had not (yet) been converted to an exception when the cleanup autocommand
+/// sequence was invoked.
+///
+/// See comment above enter_cleanup() for how this function is used.
+///
+/// This function has to be called with the address of the cleanup_T structure
+/// filled by enter_cleanup() as an argument; it restores the error/interrupt/
+/// exception state saved by that function - except there was an aborting
+/// error, an interrupt or an uncaught exception during execution of the
+/// cleanup autocommands. In the latter case, the saved error/interrupt/
+/// exception state is discarded.
void leave_cleanup(cleanup_T *csp)
{
int pending = csp->pending;
@@ -1912,23 +1866,25 @@ void leave_cleanup(cleanup_T *csp)
}
}
-
-/*
- * Make conditionals inactive and discard what's pending in finally clauses
- * until the conditional type searched for or a try conditional not in its
- * finally clause is reached. If this is in an active catch clause, finish
- * the caught exception.
- * Return the cstack index where the search stopped.
- * Values used for "searched_cond" are (CSF_WHILE | CSF_FOR) or CSF_TRY or 0,
- * the latter meaning the innermost try conditional not in its finally clause.
- * "inclusive" tells whether the conditional searched for should be made
- * inactive itself (a try conditional not in its finally clause possibly find
- * before is always made inactive). If "inclusive" is TRUE and
- * "searched_cond" is CSF_TRY|CSF_SILENT, the saved former value of
- * "emsg_silent", if reset when the try conditional finally reached was
- * entered, is restored (used by ex_endtry()). This is normally done only
- * when such a try conditional is left.
- */
+/// Make conditionals inactive and discard what's pending in finally clauses
+/// until the conditional type searched for or a try conditional not in its
+/// finally clause is reached. If this is in an active catch clause, finish
+/// the caught exception.
+///
+///
+/// @param searched_cond Possible values are (CSF_WHILE | CSF_FOR) or CSF_TRY or 0,
+/// the latter meaning the innermost try conditional not
+/// in its finally clause.
+/// @param inclusive tells whether the conditional searched for should be made
+/// inactive itself (a try conditional not in its finally
+/// clause possibly find before is always made inactive).
+///
+/// If "inclusive" is TRUE and "searched_cond" is CSF_TRY|CSF_SILENT, the saved
+/// former value of "emsg_silent", if reset when the try conditional finally
+/// reached was entered, is restored (used by ex_endtry()). This is normally
+/// done only when such a try conditional is left.
+///
+/// @return the cstack index where the search stopped.
int cleanup_conditionals(cstack_T *cstack, int searched_cond, int inclusive)
{
int idx;
@@ -1963,7 +1919,7 @@ int cleanup_conditionals(cstack_T *cstack, int searched_cond, int inclusive)
default:
if (cstack->cs_flags[idx] & CSF_FINALLY) {
- if (cstack->cs_pending[idx] & CSTP_THROW) {
+ if ((cstack->cs_pending[idx] & CSTP_THROW) && cstack->cs_exception[idx] != NULL) {
// Cancel the pending exception. This is in the
// finally clause, so that the stack of the
// caught exceptions is not involved.
@@ -1984,8 +1940,9 @@ int cleanup_conditionals(cstack_T *cstack, int searched_cond, int inclusive)
*/
if (!(cstack->cs_flags[idx] & CSF_FINALLY)) {
if ((cstack->cs_flags[idx] & CSF_ACTIVE)
- && (cstack->cs_flags[idx] & CSF_CAUGHT)) {
+ && (cstack->cs_flags[idx] & CSF_CAUGHT) && !(cstack->cs_flags[idx] & CSF_FINISHED)) {
finish_exception((except_T *)cstack->cs_exception[idx]);
+ cstack->cs_flags[idx] |= CSF_FINISHED;
}
// Stop at this try conditional - except the try block never
// got active (because of an inactive surrounding conditional
@@ -2037,9 +1994,7 @@ int cleanup_conditionals(cstack_T *cstack, int searched_cond, int inclusive)
return idx;
}
-/*
- * Return an appropriate error message for a missing endwhile/endfor/endif.
- */
+/// @return an appropriate error message for a missing endwhile/endfor/endif.
static char *get_end_emsg(cstack_T *cstack)
{
if (cstack->cs_flags[cstack->cs_idx] & CSF_WHILE) {
@@ -2051,14 +2006,11 @@ static char *get_end_emsg(cstack_T *cstack)
return e_endif;
}
-
-/*
- * Rewind conditionals until index "idx" is reached. "cond_type" and
- * "cond_level" specify a conditional type and the address of a level variable
- * which is to be decremented with each skipped conditional of the specified
- * type.
- * Also free "for info" structures where needed.
- */
+/// Rewind conditionals until index "idx" is reached. "cond_type" and
+/// "cond_level" specify a conditional type and the address of a level variable
+/// which is to be decremented with each skipped conditional of the specified
+/// type.
+/// Also free "for info" structures where needed.
void rewind_conditionals(cstack_T *cstack, int idx, int cond_type, int *cond_level)
{
while (cstack->cs_idx > idx) {
@@ -2072,18 +2024,14 @@ void rewind_conditionals(cstack_T *cstack, int idx, int cond_type, int *cond_lev
}
}
-/*
- * ":endfunction" when not after a ":function"
- */
+/// Handle ":endfunction" when not after a ":function"
void ex_endfunction(exarg_T *eap)
{
emsg(_("E193: :endfunction not inside a function"));
}
-/*
- * Return TRUE if the string "p" looks like a ":while" or ":for" command.
- */
-int has_loop_cmd(char_u *p)
+/// @return TRUE if the string "p" looks like a ":while" or ":for" command.
+int has_loop_cmd(char *p)
{
int len;
@@ -2104,4 +2052,3 @@ int has_loop_cmd(char_u *p)
}
return FALSE;
}
-