Mercurial > octave
comparison libinterp/parse-tree/oct-parse.yy @ 27471:fd32c1a9b1bd
revamp error handling
In "error" and similar functions that ultimately call it, simply throw
an exception that contains information about the error (message, id,
stack info) instead of printing an error message immediately and then
throwing an exception. The new approach is more flexible and sllows
for some simplification of the error message routines as they no
longer need feedback from the interpreter to know when to display or
buffer messages. It is now the responsibility of any code that
catches an execution exception to determine whether and when to
display error messages.
* quit.h, quit.cc (class frame_info): New class.
(execution_exception::m_err_type, execution_exception::m_id,
execution_exception::m_message, execution_exception::m_stack_info):
New data members.
(class execution_exception): Store error type, message, id, and stack
info. Provide methods setting and accessing data as needed and for
generating stack trace message from stack info.
(execution_exception::m_stack_trace): Delete data member.
execution_exception::set_stack_trace): Delete method.
(execution_exception::set_err_type, execution_exception::err_type,
execution_exception::stack_trace, execution_exception::set_identifier,
execution_exception::identifier, execution_exception::message,
execution_exception::set_stack_info, execution_exception::display):
New methods.
* call-stack.cc, call-stack.h (call_stack::backtrace_info):
New functions.
* oct-parse.yy (maybe_print_last_error_message): Delete function and
all uses.
* pt-eval.h, pt-eval.cc (tree_evaluator::backtrace_info,
tree_evaluator::backtrace_message): New functions.
(tree_evaluator::backtrace): Now const.
(tree_evaluator::visit_unwind_protect_command,
tree_evaluator::do_unwind_protect_cleanup_code,
tree_evaluator::visit_try_catch_command, tree_evaluator::evalin,
tree_evaluator::eval, tree_evaluator::repl, debugger::repl): Save
current exception info.
* interpreter.h, interpreter.cc (interpreter::handle_exception):
New function. Use it in place of direct calls to
error_system::save_exception, error_system::display_exception (or
execution_exception::display) and interpreter::recover_from_exception,
so that we have uniform behavior when responding to an execution
exception.
* error.h, error.cc (error_system::m_buffer_error_messages,
error_system::m_discard_error_messages, error_system::m_in_try_catch):
Delete data members and associated functions. Remove all uses.
Because the error system no longer displays messages immediately,
it does not need to track whether to discard or buffer error messages
or know whether error and warning functions are invoked inside of
try-catch blocks. Everywhere that catches execution_exceptions must
now handle saving the exception state (for lasterror) and displaying
the error message and traceback as needed.
(): Delete functions and all uses.
(error_stack_frame): Delete struct definition.
(verror, vpr_where, pr_where_internal, pr_where, maybe_enter_debugger,
make_execution_exception, vmessage_with_id, message_with_id,
error_system::maybe_enter_debugger, reset_error_handler,
error_system::reset): Delete functions and all uses.
(error_system::try_option): Delete enum and all uses.
(vusage, error_1, error_system::vwarning,
error_system::rethrow_error, error_system::interpreter_try):
Simplify.
(format_message, make_stack_map, error_system::throw_error,
error_system::save_exception, error_system::display_exception):
New functions.
(Ferror): Update for error_system changes.
author | John W. Eaton <jwe@octave.org> |
---|---|
date | Fri, 04 Oct 2019 01:15:13 -0400 |
parents | 2f4e8dce06da |
children | 3fec8e9fa2aa |
comparison
equal
deleted
inserted
replaced
27470:96d4094585da | 27471:fd32c1a9b1bd |
---|---|
2502 interpreter& interp = __get_interpreter__ ("finish_colon_expression"); | 2502 interpreter& interp = __get_interpreter__ ("finish_colon_expression"); |
2503 error_system& es = interp.get_error_system (); | 2503 error_system& es = interp.get_error_system (); |
2504 | 2504 |
2505 unwind_protect frame; | 2505 unwind_protect frame; |
2506 | 2506 |
2507 frame.add_method (es, &error_system::set_discard_error_messages, | |
2508 es.discard_error_messages ()); | |
2509 frame.add_method (es, &error_system::set_discard_warning_messages, | 2507 frame.add_method (es, &error_system::set_discard_warning_messages, |
2510 es.discard_warning_messages ()); | 2508 es.discard_warning_messages ()); |
2511 | 2509 |
2512 es.discard_error_messages (true); | |
2513 es.discard_warning_messages (true); | 2510 es.discard_warning_messages (true); |
2514 | 2511 |
2515 if (! base || ! limit) | 2512 if (! base || ! limit) |
2516 { | 2513 { |
2517 delete base; | 2514 delete base; |
4170 interpreter& interp = __get_interpreter__ ("finish_array_list"); | 4167 interpreter& interp = __get_interpreter__ ("finish_array_list"); |
4171 error_system& es = interp.get_error_system (); | 4168 error_system& es = interp.get_error_system (); |
4172 | 4169 |
4173 unwind_protect frame; | 4170 unwind_protect frame; |
4174 | 4171 |
4175 frame.add_method (es, &error_system::set_discard_error_messages, | |
4176 es.discard_error_messages ()); | |
4177 frame.add_method (es, &error_system::set_discard_warning_messages, | 4172 frame.add_method (es, &error_system::set_discard_warning_messages, |
4178 es.discard_warning_messages ()); | 4173 es.discard_warning_messages ()); |
4179 | 4174 |
4180 es.discard_error_messages (true); | |
4181 es.discard_warning_messages (true); | 4175 es.discard_warning_messages (true); |
4182 | 4176 |
4183 if (array_list->all_elements_are_constant ()) | 4177 if (array_list->all_elements_are_constant ()) |
4184 { | 4178 { |
4185 try | 4179 try |
5164 | 5158 |
5165 return interp.evalin (context, try_code, nargout); | 5159 return interp.evalin (context, try_code, nargout); |
5166 } | 5160 } |
5167 | 5161 |
5168 static void | 5162 static void |
5169 maybe_print_last_error_message (bool *doit) | |
5170 { | |
5171 if (doit && *doit) | |
5172 { | |
5173 // Print error message again, which was lost because of the stderr | |
5174 // buffer. Note: this keeps error_state and last_error_stack | |
5175 // intact. | |
5176 | |
5177 octave::error_system& es | |
5178 = octave::__get_error_system__ ("maybe_print_last_error_message"); | |
5179 | |
5180 std::string id = es.last_error_id (); | |
5181 std::string msg = es.last_error_message (); | |
5182 | |
5183 message_with_id ("error", id.c_str (), "%s", msg.c_str ()); | |
5184 } | |
5185 } | |
5186 | |
5187 static void | |
5188 restore_octave_stdout (std::streambuf *buf) | 5163 restore_octave_stdout (std::streambuf *buf) |
5189 { | 5164 { |
5190 octave_stdout.flush (); | 5165 octave_stdout.flush (); |
5191 octave_stdout.rdbuf (buf); | 5166 octave_stdout.rdbuf (buf); |
5192 } | 5167 } |
5225 @end group | 5200 @end group |
5226 @end example | 5201 @end example |
5227 @seealso{eval, diary} | 5202 @seealso{eval, diary} |
5228 @end deftypefn */) | 5203 @end deftypefn */) |
5229 { | 5204 { |
5205 octave_value_list retval; | |
5206 | |
5230 int nargin = args.length (); | 5207 int nargin = args.length (); |
5231 | 5208 |
5232 if (nargin == 0 || nargin > 2) | 5209 if (nargin == 0 || nargin > 2) |
5233 print_usage (); | 5210 print_usage (); |
5234 | 5211 |
5242 err_stream.flush (); | 5219 err_stream.flush (); |
5243 | 5220 |
5244 std::streambuf* old_out_buf = out_stream.rdbuf (buffer.rdbuf ()); | 5221 std::streambuf* old_out_buf = out_stream.rdbuf (buffer.rdbuf ()); |
5245 std::streambuf* old_err_buf = err_stream.rdbuf (buffer.rdbuf ()); | 5222 std::streambuf* old_err_buf = err_stream.rdbuf (buffer.rdbuf ()); |
5246 | 5223 |
5247 bool eval_error_occurred = true; | |
5248 | |
5249 octave::unwind_protect frame; | 5224 octave::unwind_protect frame; |
5250 | 5225 |
5251 frame.add_fcn (maybe_print_last_error_message, &eval_error_occurred); | |
5252 frame.add_fcn (restore_octave_stdout, old_out_buf); | 5226 frame.add_fcn (restore_octave_stdout, old_out_buf); |
5253 frame.add_fcn (restore_octave_stderr, old_err_buf); | 5227 frame.add_fcn (restore_octave_stderr, old_err_buf); |
5254 | 5228 |
5255 // call standard eval function | 5229 // call standard eval function |
5256 octave_value_list retval; | 5230 |
5257 int eval_nargout = std::max (0, nargout - 1); | 5231 int eval_nargout = std::max (0, nargout - 1); |
5258 | 5232 |
5259 retval = Feval (interp, args, eval_nargout); | 5233 try |
5260 eval_error_occurred = false; | 5234 { |
5235 retval = Feval (interp, args, eval_nargout); | |
5236 } | |
5237 catch (const octave::execution_exception& ee) | |
5238 { | |
5239 buffer << "error: " << ee.message () << std::endl; | |
5240 | |
5241 throw; | |
5242 } | |
5261 | 5243 |
5262 retval.prepend (buffer.str ()); | 5244 retval.prepend (buffer.str ()); |
5245 | |
5263 return retval; | 5246 return retval; |
5264 } | 5247 } |
5265 | 5248 |
5266 /* | 5249 /* |
5267 | 5250 |
5333 %!error <foo> (evalc ("error ('foo')")) | 5316 %!error <foo> (evalc ("error ('foo')")) |
5334 %!error <bar> (evalc ("error ('foo')", "error ('bar')")) | 5317 %!error <bar> (evalc ("error ('foo')", "error ('bar')")) |
5335 | 5318 |
5336 %!test | 5319 %!test |
5337 %! warning ("off", "quiet", "local"); | 5320 %! warning ("off", "quiet", "local"); |
5338 %! assert (evalc ("warning ('foo')"), "warning: foo\n"); | 5321 %! str = evalc ("warning ('foo')"); |
5322 %! assert (str(1:13), "warning: foo\n"); | |
5339 | 5323 |
5340 %!test | 5324 %!test |
5341 %! warning ("off", "quiet", "local"); | 5325 %! warning ("off", "quiet", "local"); |
5342 %! assert (evalc ("error ('foo')", "warning ('bar')"), "warning: bar\n"); | 5326 %! str = evalc ("error ('foo')", "warning ('bar')"); |
5327 %! assert (str(1:13), "warning: bar\n"); | |
5343 | 5328 |
5344 %!error evalc ("switch = 13;") | 5329 %!error evalc ("switch = 13;") |
5345 | 5330 |
5346 */ | 5331 */ |
5347 | 5332 |