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