aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/ex_eval.c
diff options
context:
space:
mode:
authorJosh Rahm <joshuarahm@gmail.com>2023-01-25 17:57:01 +0000
committerJosh Rahm <joshuarahm@gmail.com>2023-01-25 17:57:01 +0000
commit9837de570c5972f98e74848edc97c297a13136ea (patch)
treecc948611912d116a3f98a744e690d3d7b6e2f59a /src/nvim/ex_eval.c
parentc367400b73d207833d51e09d663f969ffab37531 (diff)
parent3c48d3c83fc21dbc0841f9210f04bdb073d73cd1 (diff)
downloadrneovim-9837de570c5972f98e74848edc97c297a13136ea.tar.gz
rneovim-9837de570c5972f98e74848edc97c297a13136ea.tar.bz2
rneovim-9837de570c5972f98e74848edc97c297a13136ea.zip
Merge remote-tracking branch 'upstream/master' into colorcolchar
Diffstat (limited to 'src/nvim/ex_eval.c')
-rw-r--r--src/nvim/ex_eval.c543
1 files changed, 280 insertions, 263 deletions
diff --git a/src/nvim/ex_eval.c b/src/nvim/ex_eval.c
index c2648b9bfc..f76e60f6c5 100644
--- a/src/nvim/ex_eval.c
+++ b/src/nvim/ex_eval.c
@@ -1,8 +1,6 @@
// This is an open source non-commercial project. Dear PVS-Studio, please check
// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
-// TODO(ZyX-I): move to eval/executor
-
/// @file ex_eval.c
///
/// Functions for Ex command line for the +eval feature.
@@ -10,19 +8,30 @@
#include <inttypes.h>
#include <limits.h>
#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
#include "nvim/ascii.h"
#include "nvim/charset.h"
#include "nvim/debugger.h"
#include "nvim/eval.h"
+#include "nvim/eval/typval.h"
+#include "nvim/eval/typval_defs.h"
#include "nvim/eval/userfunc.h"
+#include "nvim/ex_cmds_defs.h"
#include "nvim/ex_docmd.h"
#include "nvim/ex_eval.h"
+#include "nvim/ex_eval_defs.h"
+#include "nvim/gettext.h"
+#include "nvim/globals.h"
#include "nvim/memory.h"
#include "nvim/message.h"
+#include "nvim/option_defs.h"
+#include "nvim/pos.h"
#include "nvim/regexp.h"
#include "nvim/runtime.h"
#include "nvim/strings.h"
+#include "nvim/types.h"
#include "nvim/vim.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
@@ -245,7 +254,7 @@ bool cause_errthrow(const char *mesg, bool severe, bool *ignore)
// Skip the extra "Vim " prefix for message "E458".
tmsg = elem->msg;
- if (STRNCMP(tmsg, "Vim E", 5) == 0
+ if (strncmp(tmsg, "Vim E", 5) == 0
&& ascii_isdigit(tmsg[5])
&& ascii_isdigit(tmsg[6])
&& ascii_isdigit(tmsg[7])
@@ -439,9 +448,9 @@ static int throw_exception(void *value, except_type_T type, char *cmdname)
// would be treated differently from real interrupt or error exceptions
// when no active try block is found, see do_cmdline().
if (type == ET_USER) {
- if (STRNCMP((char_u *)value, "Vim", 3) == 0
- && (((char_u *)value)[3] == NUL || ((char_u *)value)[3] == ':'
- || ((char_u *)value)[3] == '(')) {
+ if (strncmp(value, "Vim", 3) == 0
+ && (((char *)value)[3] == NUL || ((char *)value)[3] == ':'
+ || ((char *)value)[3] == '(')) {
emsg(_("E608: Cannot :throw exceptions with 'Vim' prefix"));
goto fail;
}
@@ -529,7 +538,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 = xstrdup((char *)IObuff);
+ saved_IObuff = xstrdup(IObuff);
if (debug_break_level > 0) {
msg_silent = false; // display messages
} else {
@@ -539,9 +548,7 @@ static void discard_exception(except_T *excp, bool was_finished)
if (debug_break_level > 0 || *p_vfile == NUL) {
msg_scroll = true; // always scroll up, don't overwrite
}
- smsg(was_finished ? _("Exception finished: %s")
- : _("Exception discarded: %s"),
- excp->value);
+ smsg(was_finished ? _("Exception finished: %s") : _("Exception discarded: %s"), excp->value);
msg_puts("\n"); // don't overwrite this either
if (debug_break_level > 0 || *p_vfile == NUL) {
cmdline_row = msg_row;
@@ -552,7 +559,7 @@ static void discard_exception(except_T *excp, bool was_finished)
} else {
verbose_leave();
}
- STRLCPY(IObuff, saved_IObuff, IOSIZE);
+ xstrlcpy(IObuff, saved_IObuff, IOSIZE);
xfree(saved_IObuff);
}
if (excp->type != ET_INTERRUPT) {
@@ -585,12 +592,12 @@ static void catch_exception(except_T *excp)
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),
+ vim_snprintf(IObuff, IOSIZE, _("%s, line %" PRId64),
excp->throw_name, (int64_t)excp->throw_lnum);
} else {
- vim_snprintf((char *)IObuff, IOSIZE, "%s", excp->throw_name);
+ vim_snprintf(IObuff, IOSIZE, "%s", excp->throw_name);
}
- set_vim_var_string(VV_THROWPOINT, (char *)IObuff, -1);
+ set_vim_var_string(VV_THROWPOINT, IObuff, -1);
} else {
// throw_name not set on an exception from a command that was typed.
set_vim_var_string(VV_THROWPOINT, NULL, -1);
@@ -634,14 +641,14 @@ static void finish_exception(except_T *excp)
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,
+ vim_snprintf(IObuff, IOSIZE,
_("%s, line %" PRId64), caught_stack->throw_name,
(int64_t)caught_stack->throw_lnum);
} else {
- vim_snprintf((char *)IObuff, IOSIZE, "%s",
+ vim_snprintf(IObuff, IOSIZE, "%s",
caught_stack->throw_name);
}
- set_vim_var_string(VV_THROWPOINT, (char *)IObuff, -1);
+ set_vim_var_string(VV_THROWPOINT, IObuff, -1);
} else {
// throw_name not set on an exception from a command that was
// typed.
@@ -707,9 +714,9 @@ static void report_pending(int action, int pending, void *value)
default:
if (pending & CSTP_THROW) {
- vim_snprintf((char *)IObuff, IOSIZE,
+ vim_snprintf(IObuff, IOSIZE,
mesg, _("Exception"));
- mesg = concat_str((char *)IObuff, ": %s");
+ mesg = concat_str(IObuff, ": %s");
s = ((except_T *)value)->value;
} else if ((pending & CSTP_ERROR) && (pending & CSTP_INTERRUPT)) {
s = _("Error and interrupt");
@@ -853,7 +860,7 @@ void ex_endif(exarg_T *eap)
/// Handle ":else" and ":elseif".
void ex_else(exarg_T *eap)
{
- int result;
+ bool result = false;
cstack_T *const cstack = eap->cstack;
bool skip = CHECK_SKIP;
@@ -901,13 +908,20 @@ void ex_else(exarg_T *eap)
if (eap->cmdidx == CMD_elseif) {
bool error;
- result = eval_to_bool(eap->arg, &error, &eap->nextcmd, skip);
+ // When skipping we ignore most errors, but a missing expression is
+ // wrong, perhaps it should have been "else".
+ // A double quote here is the start of a string, not a comment.
+ if (skip && *eap->arg != '"' && ends_excmd(*eap->arg)) {
+ semsg(_(e_invexpr2), eap->arg);
+ } else {
+ result = eval_to_bool(eap->arg, &error, &eap->nextcmd, skip);
+ }
+
// When throwing error exceptions, we want to throw always the first
// of several errors in a row. This is what actually happens when
// a conditional error was detected above and there is another failure
// when parsing the expression. Since the skip flag is set in this
// case, the parsing error will be ignored by emsg().
-
if (!skip && !error) {
if (result) {
cstack->cs_flags[cstack->cs_idx] = CSF_ACTIVE | CSF_TRUE;
@@ -1085,7 +1099,7 @@ void ex_endwhile(exarg_T *eap)
}
// Try to find the matching ":while" and report what's missing.
for (idx = cstack->cs_idx; idx > 0; idx--) {
- fl = cstack->cs_flags[idx];
+ fl = cstack->cs_flags[idx];
if ((fl & CSF_TRY) && !(fl & CSF_FINALLY)) {
// Give up at a try conditional not in its finally clause.
// Ignore the ":endwhile"/":endfor".
@@ -1136,7 +1150,7 @@ void ex_throw(exarg_T *eap)
// On error or when an exception is thrown during argument evaluation, do
// not throw.
if (!eap->skip && value != NULL) {
- if (throw_exception((char_u *)value, ET_USER, NULL) == FAIL) {
+ if (throw_exception(value, ET_USER, NULL) == FAIL) {
xfree(value);
} else {
do_throw(eap->cstack);
@@ -1298,7 +1312,10 @@ void ex_catch(exarg_T *eap)
eap->nextcmd = find_nextcmd(eap->arg);
} else {
pat = eap->arg + 1;
- end = skip_regexp(pat, *eap->arg, true, NULL);
+ end = skip_regexp_err(pat, *eap->arg, true);
+ if (end == NULL) {
+ give_up = true;
+ }
}
if (!give_up) {
@@ -1355,8 +1372,7 @@ void ex_catch(exarg_T *eap)
//
prev_got_int = got_int;
got_int = false;
- caught = vim_regexec_nl(&regmatch, (char_u *)current_exception->value,
- (colnr_T)0);
+ caught = vim_regexec_nl(&regmatch, current_exception->value, (colnr_T)0);
got_int |= prev_got_int;
vim_regfree(regmatch.regprog);
}
@@ -1403,108 +1419,107 @@ void ex_finally(exarg_T *eap)
int pending = CSTP_NONE;
cstack_T *const cstack = eap->cstack;
- if (cstack->cs_trylevel <= 0 || cstack->cs_idx < 0) {
- eap->errmsg = _("E606: :finally without :try");
- } else {
- if (!(cstack->cs_flags[cstack->cs_idx] & CSF_TRY)) {
- eap->errmsg = get_end_emsg(cstack);
- for (idx = cstack->cs_idx - 1; idx > 0; idx--) {
- if (cstack->cs_flags[idx] & CSF_TRY) {
- break;
- }
- }
- // Make this error pending, so that the commands in the following
- // finally clause can be executed. This overrules also a pending
- // ":continue", ":break", ":return", or ":finish".
- pending = CSTP_ERROR;
- } else {
- idx = cstack->cs_idx;
+ for (idx = cstack->cs_idx; idx >= 0; idx--) {
+ if (cstack->cs_flags[idx] & CSF_TRY) {
+ break;
}
+ }
+ if (cstack->cs_trylevel <= 0 || idx < 0) {
+ eap->errmsg = _("E606: :finally without :try");
+ return;
+ }
- if (cstack->cs_flags[idx] & CSF_FINALLY) {
- // Give up for a multiple ":finally" and ignore it.
- eap->errmsg = _("E607: multiple :finally");
- return;
- }
- rewind_conditionals(cstack, idx, CSF_WHILE | CSF_FOR,
- &cstack->cs_looplevel);
+ if (!(cstack->cs_flags[cstack->cs_idx] & CSF_TRY)) {
+ eap->errmsg = get_end_emsg(cstack);
+ // Make this error pending, so that the commands in the following
+ // finally clause can be executed. This overrules also a pending
+ // ":continue", ":break", ":return", or ":finish".
+ pending = CSTP_ERROR;
+ }
- // Don't do something when the corresponding try block never got active
- // (because of an inactive surrounding conditional or after an error or
- // 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.
- skip = !(cstack->cs_flags[cstack->cs_idx] & CSF_TRUE);
+ if (cstack->cs_flags[idx] & CSF_FINALLY) {
+ // Give up for a multiple ":finally" and ignore it.
+ eap->errmsg = _("E607: multiple :finally");
+ return;
+ }
+ rewind_conditionals(cstack, idx, CSF_WHILE | CSF_FOR,
+ &cstack->cs_looplevel);
+
+ // Don't do something when the corresponding try block never got active
+ // (because of an inactive surrounding conditional or after an error or
+ // 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.
+ skip = !(cstack->cs_flags[cstack->cs_idx] & CSF_TRUE);
+
+ if (!skip) {
+ // When debugging or a breakpoint was encountered, display the
+ // debug prompt (if not already done). The user then knows that the
+ // finally clause is executed.
+ if (dbg_check_skipped(eap)) {
+ // Handle a ">quit" debug command as if an interrupt had
+ // occurred before the ":finally". That is, discard the
+ // original exception and replace it by an interrupt
+ // exception.
+ (void)do_intthrow(cstack);
+ }
- if (!skip) {
- // When debugging or a breakpoint was encountered, display the
- // debug prompt (if not already done). The user then knows that the
- // finally clause is executed.
- if (dbg_check_skipped(eap)) {
- // Handle a ">quit" debug command as if an interrupt had
- // occurred before the ":finally". That is, discard the
- // original exception and replace it by an interrupt
- // exception.
- (void)do_intthrow(cstack);
+ // If there is a preceding catch clause and it caught the exception,
+ // finish the exception now. This happens also after errors except
+ // when this is a multiple ":finally" or one not within a ":try".
+ // After an error or interrupt, this also discards a pending
+ // ":continue", ":break", ":finish", or ":return" from the preceding
+ // try block or catch clause.
+ 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
+ // 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
+ // already been set, respectively in case that the error is not
+ // converted to an exception, did_throw 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 (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 there is a preceding catch clause and it caught the exception,
- // finish the exception now. This happens also after errors except
- // when this is a multiple ":finally" or one not within a ":try".
- // After an error or interrupt, this also discards a pending
- // ":continue", ":break", ":finish", or ":return" from the preceding
- // try block or catch clause.
- 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
- // 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
- // already been set, respectively in case that the error is not
- // converted to an exception, did_throw 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 (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);
- }
- pending |= did_emsg ? CSTP_ERROR : 0;
- pending |= got_int ? CSTP_INTERRUPT : 0;
- assert(pending >= CHAR_MIN && pending <= CHAR_MAX);
- cstack->cs_pending[cstack->cs_idx] = (char)pending;
-
- // It's mandatory that the current exception is stored in the
- // cstack so that it can be rethrown at the ":endtry" or be
- // discarded if the finally clause is left by a ":continue",
- // ":break", ":return", ":finish", error, interrupt, or another
- // 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) {
- internal_error("ex_finally()");
- }
+ if (pending == CSTP_ERROR && !did_emsg) {
+ pending |= (THROW_ON_ERROR ? CSTP_THROW : 0);
+ } else {
+ pending |= (did_throw ? CSTP_THROW : 0);
+ }
+ pending |= did_emsg ? CSTP_ERROR : 0;
+ pending |= got_int ? CSTP_INTERRUPT : 0;
+ assert(pending >= CHAR_MIN && pending <= CHAR_MAX);
+ cstack->cs_pending[cstack->cs_idx] = (char)pending;
+
+ // It's mandatory that the current exception is stored in the
+ // cstack so that it can be rethrown at the ":endtry" or be
+ // discarded if the finally clause is left by a ":continue",
+ // ":break", ":return", ":finish", error, interrupt, or another
+ // 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) {
+ 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.
- // 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.
- cstack->cs_lflags |= CSL_HAD_FINA;
}
+
+ // Set CSL_HAD_FINA, so do_cmdline() will reset did_emsg,
+ // got_int, and did_throw 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.
+ cstack->cs_lflags |= CSL_HAD_FINA;
}
}
@@ -1517,165 +1532,167 @@ void ex_endtry(exarg_T *eap)
void *rettv = NULL;
cstack_T *const cstack = eap->cstack;
- if (cstack->cs_trylevel <= 0 || cstack->cs_idx < 0) {
+ for (idx = cstack->cs_idx; idx >= 0; idx--) {
+ if (cstack->cs_flags[idx] & CSF_TRY) {
+ break;
+ }
+ }
+ if (cstack->cs_trylevel <= 0 || idx < 0) {
eap->errmsg = _("E602: :endtry without :try");
- } else {
- // Don't do something after an error, interrupt or throw in the try
- // block, catch clause, or finally clause preceding this ":endtry" or
- // when an error or interrupt occurred after a ":continue", ":break",
- // ":return", or ":finish" in a try block or catch clause preceding this
- // ":endtry" or when the try block never got active (because of an
- // inactive surrounding conditional or after an error or interrupt or
- // throw) or when there is a surrounding conditional and it has been
- // 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.
- bool skip = did_emsg || got_int || did_throw || !(cstack->cs_flags[cstack->cs_idx] & CSF_TRUE);
+ return;
+ }
- if (!(cstack->cs_flags[cstack->cs_idx] & CSF_TRY)) {
- eap->errmsg = get_end_emsg(cstack);
+ // Don't do something after an error, interrupt or throw in the try
+ // block, catch clause, or finally clause preceding this ":endtry" or
+ // when an error or interrupt occurred after a ":continue", ":break",
+ // ":return", or ":finish" in a try block or catch clause preceding this
+ // ":endtry" or when the try block never got active (because of an
+ // inactive surrounding conditional or after an error or interrupt or
+ // throw) or when there is a surrounding conditional and it has been
+ // 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.
+ bool skip = did_emsg || got_int || did_throw || !(cstack->cs_flags[cstack->cs_idx] & CSF_TRUE);
- // Find the matching ":try" and report what's missing.
- idx = cstack->cs_idx;
- do {
- idx--;
- } while (idx > 0 && !(cstack->cs_flags[idx] & CSF_TRY));
- rewind_conditionals(cstack, idx, CSF_WHILE | CSF_FOR,
- &cstack->cs_looplevel);
- skip = true;
+ if (!(cstack->cs_flags[cstack->cs_idx] & CSF_TRY)) {
+ eap->errmsg = get_end_emsg(cstack);
- // 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.
- // This does not affect the script termination due to the error
- // since "trylevel" is decremented after emsg() has been called.
- if (did_throw) {
- discard_current_exception();
- }
+ // Find the matching ":try" and report what's missing.
+ rewind_conditionals(cstack, idx, CSF_WHILE | CSF_FOR,
+ &cstack->cs_looplevel);
+ skip = true;
- // report eap->errmsg, also when there already was an error
- did_emsg = false;
- } else {
- idx = cstack->cs_idx;
-
- // If we stopped with the exception currently being thrown at this
- // try conditional since we didn't know that it doesn't have
- // 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 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.
+ // This does not affect the script termination due to the error
+ // since "trylevel" is decremented after emsg() has been called.
+ if (did_throw) {
+ discard_current_exception();
}
- // If there was no finally clause, show the user when debugging or
- // a breakpoint was encountered that the end of the try conditional has
- // been reached: display the debug prompt (if not already done). Do
- // this on normal control flow or when an exception was thrown, but not
- // on an interrupt or error not converted to an exception or when
- // a ":break", ":continue", ":return", or ":finish" is pending. These
- // actions are carried out immediately.
- if ((rethrow || (!skip
- && !(cstack->cs_flags[idx] & CSF_FINALLY)
- && !cstack->cs_pending[idx]))
- && dbg_check_skipped(eap)) {
- // Handle a ">quit" debug command as if an interrupt had occurred
- // before the ":endtry". That is, throw an interrupt exception and
- // set "skip" and "rethrow".
- 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;
- }
+ // report eap->errmsg, also when there already was an error
+ did_emsg = false;
+ } else {
+ idx = cstack->cs_idx;
+
+ // If we stopped with the exception currently being thrown at this
+ // try conditional since we didn't know that it doesn't have
+ // 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 there was no finally clause, show the user when debugging or
+ // a breakpoint was encountered that the end of the try conditional has
+ // been reached: display the debug prompt (if not already done). Do
+ // this on normal control flow or when an exception was thrown, but not
+ // on an interrupt or error not converted to an exception or when
+ // a ":break", ":continue", ":return", or ":finish" is pending. These
+ // actions are carried out immediately.
+ if ((rethrow || (!skip
+ && !(cstack->cs_flags[idx] & CSF_FINALLY)
+ && !cstack->cs_pending[idx]))
+ && dbg_check_skipped(eap)) {
+ // Handle a ">quit" debug command as if an interrupt had occurred
+ // before the ":endtry". That is, throw an interrupt exception and
+ // set "skip" and "rethrow".
+ 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;
}
}
+ }
- // If a ":return" is pending, we need to resume it after closing the
- // try conditional; remember the return value. If there was a finally
- // clause making an exception pending, we need to rethrow it. Make it
- // the exception currently being thrown.
- if (!skip) {
- pending = cstack->cs_pending[idx];
- cstack->cs_pending[idx] = CSTP_NONE;
- if (pending == CSTP_RETURN) {
- rettv = cstack->cs_rettv[idx];
- } else if (pending & CSTP_THROW) {
- current_exception = cstack->cs_exception[idx];
- }
+ // If a ":return" is pending, we need to resume it after closing the
+ // try conditional; remember the return value. If there was a finally
+ // clause making an exception pending, we need to rethrow it. Make it
+ // the exception currently being thrown.
+ if (!skip) {
+ pending = cstack->cs_pending[idx];
+ cstack->cs_pending[idx] = CSTP_NONE;
+ if (pending == CSTP_RETURN) {
+ rettv = cstack->cs_rettv[idx];
+ } else if (pending & CSTP_THROW) {
+ current_exception = cstack->cs_exception[idx];
}
+ }
- // Discard anything pending on an error, interrupt, or throw in the
- // finally clause. If there was no ":finally", discard a pending
- // ":continue", ":break", ":return", or ":finish" if an error or
- // interrupt occurred afterwards, but before the ":endtry" was reached.
- // If an exception was caught by the last of the catch clauses and there
- // was no finally clause, finish the exception now. This happens also
- // after errors except when this ":endtry" is not within a ":try".
- // Restore "emsg_silent" if it has been reset by this try conditional.
- (void)cleanup_conditionals(cstack, CSF_TRY | CSF_SILENT, true);
+ // Discard anything pending on an error, interrupt, or throw in the
+ // finally clause. If there was no ":finally", discard a pending
+ // ":continue", ":break", ":return", or ":finish" if an error or
+ // interrupt occurred afterwards, but before the ":endtry" was reached.
+ // If an exception was caught by the last of the catch clauses and there
+ // was no finally clause, finish the exception now. This happens also
+ // after errors except when this ":endtry" is not within a ":try".
+ // Restore "emsg_silent" if it has been reset by this try conditional.
+ (void)cleanup_conditionals(cstack, CSF_TRY | CSF_SILENT, true);
- if (cstack->cs_idx >= 0 && (cstack->cs_flags[cstack->cs_idx] & CSF_TRY)) {
- 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,
- (pending == CSTP_RETURN) ? rettv :
- (pending & CSTP_THROW) ? (void *)current_exception : NULL);
- switch (pending) {
- case CSTP_NONE:
- break;
+ if (!skip) {
+ report_resume_pending(pending,
+ (pending == CSTP_RETURN) ? rettv :
+ (pending & CSTP_THROW) ? (void *)current_exception : NULL);
+ switch (pending) {
+ case CSTP_NONE:
+ break;
- // Reactivate a pending ":continue", ":break", ":return",
- // ":finish" from the try block or a catch clause of this try
- // conditional. This is skipped, if there was an error in an
- // (unskipped) conditional command or an interrupt afterwards
- // or if the finally clause is present and executed a new error,
- // interrupt, throw, ":continue", ":break", ":return", or
- // ":finish".
- case CSTP_CONTINUE:
- ex_continue(eap);
- break;
- case CSTP_BREAK:
- ex_break(eap);
- break;
- case CSTP_RETURN:
- do_return(eap, false, false, rettv);
- break;
- case CSTP_FINISH:
- do_finish(eap, false);
- break;
+ // Reactivate a pending ":continue", ":break", ":return",
+ // ":finish" from the try block or a catch clause of this try
+ // conditional. This is skipped, if there was an error in an
+ // (unskipped) conditional command or an interrupt afterwards
+ // or if the finally clause is present and executed a new error,
+ // interrupt, throw, ":continue", ":break", ":return", or
+ // ":finish".
+ case CSTP_CONTINUE:
+ ex_continue(eap);
+ break;
+ case CSTP_BREAK:
+ ex_break(eap);
+ break;
+ case CSTP_RETURN:
+ do_return(eap, false, false, rettv);
+ break;
+ case CSTP_FINISH:
+ 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.
- default:
- if (pending & CSTP_ERROR) {
- did_emsg = true;
- }
- if (pending & CSTP_INTERRUPT) {
- got_int = true;
- }
- if (pending & CSTP_THROW) {
- rethrow = true;
- }
- 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.
+ default:
+ 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).
- do_throw(cstack);
- }
+ if (rethrow) {
+ // Rethrow the current exception (within this cstack).
+ do_throw(cstack);
}
}
@@ -1950,7 +1967,7 @@ void rewind_conditionals(cstack_T *cstack, int idx, int cond_type, int *cond_lev
{
while (cstack->cs_idx > idx) {
if (cstack->cs_flags[cstack->cs_idx] & cond_type) {
- --*cond_level;
+ (*cond_level)--;
}
if (cstack->cs_flags[cstack->cs_idx] & CSF_FOR) {
free_for_info(cstack->cs_forinfo[cstack->cs_idx]);