Mercurial > octave
comparison libinterp/corefcn/error.cc @ 31608:23664317f0d3
maint: merge stable to default
author | Rik <rik@octave.org> |
---|---|
date | Thu, 01 Dec 2022 20:05:44 -0800 |
parents | dfa5d9c3ae72 aac27ad79be6 |
children | 5c6395400843 |
comparison
equal
deleted
inserted
replaced
31606:dfa5d9c3ae72 | 31608:23664317f0d3 |
---|---|
233 return have_fmt; | 233 return have_fmt; |
234 } | 234 } |
235 | 235 |
236 OCTAVE_BEGIN_NAMESPACE(octave) | 236 OCTAVE_BEGIN_NAMESPACE(octave) |
237 | 237 |
238 static octave_scalar_map | 238 static octave_scalar_map |
239 init_warning_options (const std::string& state) | 239 init_warning_options (const std::string& state) |
240 { | 240 { |
241 octave_scalar_map initw; | 241 octave_scalar_map initw; |
242 | 242 |
243 initw.setfield ("identifier", "all"); | 243 initw.setfield ("identifier", "all"); |
244 initw.setfield ("state", state); | 244 initw.setfield ("state", state); |
245 | 245 |
246 return initw; | 246 return initw; |
247 } | 247 } |
248 | 248 |
249 static octave_map | 249 static octave_map |
250 init_error_stack (interpreter& interp) | 250 init_error_stack (interpreter& interp) |
251 { | 251 { |
252 tree_evaluator& tw = interp.get_evaluator (); | 252 tree_evaluator& tw = interp.get_evaluator (); |
253 | 253 |
254 return tw.empty_backtrace (); | 254 return tw.empty_backtrace (); |
255 } | 255 } |
256 | 256 |
257 error_system::error_system (interpreter& interp) | 257 error_system::error_system (interpreter& interp) |
258 : m_interpreter (interp), | 258 : m_interpreter (interp), |
259 m_debug_on_error (false), | 259 m_debug_on_error (false), |
260 m_debug_on_caught (false), | 260 m_debug_on_caught (false), |
261 m_debug_on_warning (false), | 261 m_debug_on_warning (false), |
262 m_discard_warning_messages (false), | 262 m_discard_warning_messages (false), |
263 m_beep_on_error (false), | 263 m_beep_on_error (false), |
264 m_backtrace_on_warning (true), | 264 m_backtrace_on_warning (true), |
265 m_verbose_warning (false), | 265 m_verbose_warning (false), |
266 m_quiet_warning (false), | 266 m_quiet_warning (false), |
267 m_warning_options (init_warning_options ("on")), | 267 m_warning_options (init_warning_options ("on")), |
268 m_last_error_message (), | 268 m_last_error_message (), |
269 m_last_warning_message (), | 269 m_last_warning_message (), |
270 m_last_warning_id (), | 270 m_last_warning_id (), |
271 m_last_error_id (), | 271 m_last_error_id (), |
272 m_last_error_stack (init_error_stack (interp)) | 272 m_last_error_stack (init_error_stack (interp)) |
273 { | 273 { |
274 initialize_default_warning_state (); | 274 initialize_default_warning_state (); |
275 } | 275 } |
276 | 276 |
277 octave_value | 277 octave_value |
278 error_system::debug_on_error (const octave_value_list& args, int nargout) | 278 error_system::debug_on_error (const octave_value_list& args, int nargout) |
279 { | 279 { |
280 return set_internal_variable (m_debug_on_error, args, nargout, | 280 return set_internal_variable (m_debug_on_error, args, nargout, |
281 "debug_on_error"); | 281 "debug_on_error"); |
282 } | 282 } |
283 | 283 |
284 octave_value | 284 octave_value |
285 error_system::debug_on_caught (const octave_value_list& args, int nargout) | 285 error_system::debug_on_caught (const octave_value_list& args, int nargout) |
286 { | 286 { |
287 return set_internal_variable (m_debug_on_caught, args, nargout, | 287 return set_internal_variable (m_debug_on_caught, args, nargout, |
288 "debug_on_caught"); | 288 "debug_on_caught"); |
289 } | 289 } |
290 | 290 |
291 octave_value | 291 octave_value |
292 error_system::debug_on_warning (const octave_value_list& args, int nargout) | 292 error_system::debug_on_warning (const octave_value_list& args, int nargout) |
293 { | 293 { |
294 return set_internal_variable (m_debug_on_warning, args, nargout, | 294 return set_internal_variable (m_debug_on_warning, args, nargout, |
295 "debug_on_warning"); | 295 "debug_on_warning"); |
296 } | 296 } |
297 | 297 |
298 octave_value | 298 octave_value |
299 error_system::discard_warning_messages (const octave_value_list& args, | 299 error_system::discard_warning_messages (const octave_value_list& args, |
300 int nargout) | 300 int nargout) |
301 { | 301 { |
302 return set_internal_variable (m_discard_warning_messages, args, nargout, | 302 return set_internal_variable (m_discard_warning_messages, args, nargout, |
303 "discard_warning_messages"); | 303 "discard_warning_messages"); |
304 } | 304 } |
305 | 305 |
306 octave_value | 306 octave_value |
307 error_system::beep_on_error (const octave_value_list& args, int nargout) | 307 error_system::beep_on_error (const octave_value_list& args, int nargout) |
308 { | 308 { |
309 return set_internal_variable (m_beep_on_error, args, nargout, | 309 return set_internal_variable (m_beep_on_error, args, nargout, |
310 "beep_on_error"); | 310 "beep_on_error"); |
311 } | 311 } |
312 | 312 |
313 octave_value | 313 octave_value |
314 error_system::backtrace_on_warning (const octave_value_list& args, | 314 error_system::backtrace_on_warning (const octave_value_list& args, |
315 int nargout) | 315 int nargout) |
316 { | 316 { |
317 return set_internal_variable (m_backtrace_on_warning, args, nargout, | 317 return set_internal_variable (m_backtrace_on_warning, args, nargout, |
318 "backtrace_on_warning"); | 318 "backtrace_on_warning"); |
319 } | 319 } |
320 | 320 |
321 octave_value | 321 octave_value |
322 error_system::verbose_warning (const octave_value_list& args, int nargout) | 322 error_system::verbose_warning (const octave_value_list& args, int nargout) |
323 { | 323 { |
324 return set_internal_variable (m_verbose_warning, args, nargout, | 324 return set_internal_variable (m_verbose_warning, args, nargout, |
325 "verbose_warning"); | 325 "verbose_warning"); |
326 } | 326 } |
327 | 327 |
328 octave_value | 328 octave_value |
329 error_system::quiet_warning (const octave_value_list& args, int nargout) | 329 error_system::quiet_warning (const octave_value_list& args, int nargout) |
330 { | 330 { |
331 return set_internal_variable (m_quiet_warning, args, nargout, | 331 return set_internal_variable (m_quiet_warning, args, nargout, |
332 "quiet_warning"); | 332 "quiet_warning"); |
333 } | 333 } |
334 | 334 |
335 octave_value | 335 octave_value |
336 error_system::last_error_message (const octave_value_list& args, int nargout) | 336 error_system::last_error_message (const octave_value_list& args, int nargout) |
337 { | 337 { |
338 return set_internal_variable (m_last_error_message, args, nargout, | 338 return set_internal_variable (m_last_error_message, args, nargout, |
339 "last_error_message"); | 339 "last_error_message"); |
340 } | 340 } |
341 | 341 |
342 octave_value | 342 octave_value |
343 error_system::last_warning_message (const octave_value_list& args, | 343 error_system::last_warning_message (const octave_value_list& args, |
344 int nargout) | 344 int nargout) |
345 { | 345 { |
346 return set_internal_variable (m_last_warning_message, args, nargout, | 346 return set_internal_variable (m_last_warning_message, args, nargout, |
347 "last_warning_message"); | 347 "last_warning_message"); |
348 } | 348 } |
349 | 349 |
350 octave_value | 350 octave_value |
351 error_system::last_warning_id (const octave_value_list& args, int nargout) | 351 error_system::last_warning_id (const octave_value_list& args, int nargout) |
352 { | 352 { |
353 return set_internal_variable (m_last_warning_id, args, nargout, | 353 return set_internal_variable (m_last_warning_id, args, nargout, |
354 "last_warning_id"); | 354 "last_warning_id"); |
355 } | 355 } |
356 | 356 |
357 octave_value | 357 octave_value |
358 error_system::last_error_id (const octave_value_list& args, int nargout) | 358 error_system::last_error_id (const octave_value_list& args, int nargout) |
359 { | 359 { |
360 return set_internal_variable (m_last_error_id, args, nargout, | 360 return set_internal_variable (m_last_error_id, args, nargout, |
361 "last_error_id"); | 361 "last_error_id"); |
362 } | 362 } |
363 | 363 |
364 // Use static fields for the best efficiency. | 364 // Use static fields for the best efficiency. |
365 // NOTE: C++0x will allow these two to be merged into one. | 365 // NOTE: C++0x will allow these two to be merged into one. |
366 static const char *bt_fieldnames[] = | 366 static const char *bt_fieldnames[] = |
367 { "file", "name", "line", "column", nullptr }; | 367 { "file", "name", "line", "column", nullptr }; |
368 | 368 |
369 static const octave_fields bt_fields (bt_fieldnames); | 369 static const octave_fields bt_fields (bt_fieldnames); |
370 | 370 |
371 octave_map | 371 octave_map |
372 error_system::make_stack_map (const std::list<frame_info>& frames) | 372 error_system::make_stack_map (const std::list<frame_info>& frames) |
373 { | 373 { |
374 std::size_t nframes = frames.size (); | 374 std::size_t nframes = frames.size (); |
375 | 375 |
376 octave_map retval (dim_vector (nframes, 1), bt_fields); | 376 octave_map retval (dim_vector (nframes, 1), bt_fields); |
377 | 377 |
378 Cell& file = retval.contents (0); | 378 Cell& file = retval.contents (0); |
379 Cell& name = retval.contents (1); | 379 Cell& name = retval.contents (1); |
380 Cell& line = retval.contents (2); | 380 Cell& line = retval.contents (2); |
381 Cell& column = retval.contents (3); | 381 Cell& column = retval.contents (3); |
382 | 382 |
383 octave_idx_type k = 0; | 383 octave_idx_type k = 0; |
384 | 384 |
385 for (const auto& frm : frames) | 385 for (const auto& frm : frames) |
386 { | 386 { |
387 file(k) = frm.file_name (); | 387 file(k) = frm.file_name (); |
388 name(k) = frm.fcn_name (); | 388 name(k) = frm.fcn_name (); |
389 line(k) = frm.line (); | 389 line(k) = frm.line (); |
390 column(k) = frm.column (); | 390 column(k) = frm.column (); |
391 | 391 |
392 k++; | 392 k++; |
393 } | 393 } |
394 | 394 |
395 return retval; | 395 return retval; |
396 } | 396 } |
397 | 397 |
398 std::list<frame_info> | 398 std::list<frame_info> |
399 error_system::make_stack_frame_list (const octave_map& stack) | 399 error_system::make_stack_frame_list (const octave_map& stack) |
400 { | 400 { |
401 std::list<frame_info> frames; | 401 std::list<frame_info> frames; |
402 | 402 |
403 Cell file = stack.contents ("file"); | 403 Cell file = stack.contents ("file"); |
404 Cell name = stack.contents ("name"); | 404 Cell name = stack.contents ("name"); |
405 Cell line = stack.contents ("line"); | 405 Cell line = stack.contents ("line"); |
406 Cell column = stack.contents ("column"); | 406 Cell column = stack.contents ("column"); |
407 | 407 |
408 octave_idx_type nel = name.numel (); | 408 octave_idx_type nel = name.numel (); |
409 | 409 |
410 for (octave_idx_type i = 0; i < nel; i++) | 410 for (octave_idx_type i = 0; i < nel; i++) |
411 frames.push_back (frame_info (file(i).string_value (), | 411 frames.push_back (frame_info (file(i).string_value (), |
412 name(i).string_value (), | 412 name(i).string_value (), |
413 line(i).int_value (), | 413 line(i).int_value (), |
414 column(i).int_value ())); | 414 column(i).int_value ())); |
415 | 415 |
416 return frames; | 416 return frames; |
417 } | 417 } |
418 | 418 |
419 // For given warning ID, return 0 if warnings are disabled, 1 if | 419 // For given warning ID, return 0 if warnings are disabled, 1 if |
420 // enabled, and 2 if the given ID should be an error instead of a | 420 // enabled, and 2 if the given ID should be an error instead of a |
421 // warning. | 421 // warning. |
422 | 422 |
423 int error_system::warning_enabled (const std::string& id) | 423 int error_system::warning_enabled (const std::string& id) |
424 { | 424 { |
425 int retval = 0; | 425 int retval = 0; |
426 | 426 |
427 int all_state = -1; | 427 int all_state = -1; |
428 int id_state = -1; | 428 int id_state = -1; |
429 | 429 |
430 octave_map opts = warning_options (); | 430 octave_map opts = warning_options (); |
431 | 431 |
432 octave_idx_type nel = opts.numel (); | 432 octave_idx_type nel = opts.numel (); |
433 | 433 |
434 if (nel > 0) | 434 if (nel > 0) |
435 { | 435 { |
436 Cell identifier = opts.contents ("identifier"); | 436 Cell identifier = opts.contents ("identifier"); |
437 Cell state = opts.contents ("state"); | 437 Cell state = opts.contents ("state"); |
438 | 438 |
439 bool all_found = false; | 439 bool all_found = false; |
440 bool id_found = false; | 440 bool id_found = false; |
441 | 441 |
442 for (octave_idx_type i = 0; i < nel; i++) | 442 for (octave_idx_type i = 0; i < nel; i++) |
443 { | 443 { |
444 octave_value ov = identifier(i); | 444 octave_value ov = identifier(i); |
445 std::string ovs = ov.string_value (); | 445 std::string ovs = ov.string_value (); |
446 | 446 |
447 if (! all_found && ovs == "all") | 447 if (! all_found && ovs == "all") |
448 { | 448 { |
449 all_state = check_state (state(i).string_value ()); | 449 all_state = check_state (state(i).string_value ()); |
450 | 450 |
451 if (all_state >= 0) | 451 if (all_state >= 0) |
452 all_found = true; | 452 all_found = true; |
453 } | 453 } |
454 | 454 |
455 if (! id_found && ovs == id) | 455 if (! id_found && ovs == id) |
456 { | 456 { |
457 id_state = check_state (state(i).string_value ()); | 457 id_state = check_state (state(i).string_value ()); |
458 | 458 |
459 if (id_state >= 0) | 459 if (id_state >= 0) |
460 id_found = true; | 460 id_found = true; |
461 } | 461 } |
462 | 462 |
463 if (all_found && id_found) | 463 if (all_found && id_found) |
464 break; | |
465 } | |
466 } | |
467 | |
468 // If "all" is not present, assume warnings are enabled. | |
469 if (all_state == -1) | |
470 all_state = 1; | |
471 | |
472 if (all_state == 0) | |
473 { | |
474 if (id_state >= 0) | |
475 retval = id_state; | |
476 } | |
477 else if (all_state == 1) | |
478 { | |
479 if (id_state == 0 || id_state == 2) | |
480 retval = id_state; | |
481 else | |
482 retval = all_state; | |
483 } | |
484 else if (all_state == 2) | |
485 { | |
486 if (id_state == 0) | |
487 retval= id_state; | |
488 else | |
489 retval = all_state; | |
490 } | |
491 | |
492 return retval; | |
493 } | |
494 | |
495 void error_system::vusage (const char *id, const char *fmt, va_list args) | |
496 { | |
497 std::string str_id = id ? id : ""; | |
498 std::string message = format_message (fmt, args); | |
499 | |
500 throw_error ("usage", str_id, message); | |
501 } | |
502 | |
503 void error_system::vwarning (const char *name, const char *id, | |
504 const char *fmt, va_list args) | |
505 { | |
506 flush_stdout (); | |
507 | |
508 std::string base_msg = format_message (fmt, args); | |
509 std::string msg_string; | |
510 | |
511 if (name) | |
512 msg_string = std::string (name) + ": "; | |
513 | |
514 msg_string += base_msg; | |
515 | |
516 bool fmt_suppresses_backtrace = false; | |
517 std::size_t fmt_len = (fmt ? strlen (fmt) : 0); | |
518 fmt_suppresses_backtrace = (fmt_len > 0 && fmt[fmt_len-1] == '\n'); | |
519 | |
520 if (! fmt_suppresses_backtrace) | |
521 msg_string += '\n'; | |
522 | |
523 last_warning_id (id); | |
524 last_warning_message (base_msg); | |
525 | |
526 if (discard_warning_messages ()) | |
527 return; | |
528 | |
529 tree_evaluator& tw = m_interpreter.get_evaluator (); | |
530 | |
531 bool in_user_code = tw.in_user_code (); | |
532 | |
533 if (! quiet_warning ()) | |
534 { | |
535 octave_diary << msg_string; | |
536 std::cerr << msg_string; | |
537 | |
538 if (! fmt_suppresses_backtrace && in_user_code | |
539 && backtrace_on_warning () | |
540 && ! discard_warning_messages ()) | |
541 { | |
542 std::string bt_msg = tw.backtrace_message (); | |
543 | |
544 if (! bt_msg.empty ()) | |
545 bt_msg = "warning: called from\n" + bt_msg; | |
546 | |
547 octave_diary << bt_msg << std::endl; | |
548 std::cerr << bt_msg << std::endl; | |
549 } | |
550 } | |
551 | |
552 bp_table& bptab = tw.get_bp_table (); | |
553 | |
554 if ((m_interpreter.interactive () | |
555 || application::forced_interactive ()) | |
556 && debug_on_warning () && in_user_code && bptab.debug_on_warn (id)) | |
557 { | |
558 unwind_protect_var<bool> restore_var (m_debug_on_warning, false); | |
559 | |
560 tw.enter_debugger (); | |
561 } | |
562 } | |
563 | |
564 void error_system::error_1 (execution_exception& ee, const char *id, | |
565 const char *fmt, va_list args) | |
566 { | |
567 ee.set_identifier (id); | |
568 ee.set_message (format_message (fmt, args)); | |
569 | |
570 throw_error (ee); | |
571 } | |
572 | |
573 void error_system::error_1 (const char *id, const char *fmt, | |
574 va_list args) | |
575 { | |
576 std::string message = format_message (fmt, args); | |
577 | |
578 std::list<frame_info> stack_info; | |
579 | |
580 throw_error ("error", id, message); | |
581 } | |
582 | |
583 void error_system::vwarning (const char *id, const char *fmt, va_list args) | |
584 { | |
585 int warn_opt = warning_enabled (id); | |
586 | |
587 if (warn_opt == 2) | |
588 { | |
589 // Handle this warning as an error. | |
590 | |
591 error_1 (id, fmt, args); | |
592 } | |
593 else if (warn_opt == 1) | |
594 vwarning ("warning", id, fmt, args); | |
595 } | |
596 | |
597 void error_system::rethrow_error (const std::string& id, | |
598 const std::string& msg, | |
599 const octave_map& stack) | |
600 { | |
601 std::list<frame_info> stack_info; | |
602 | |
603 execution_exception ee ("error", id, msg, stack_info); | |
604 | |
605 if (! stack.isempty ()) | |
606 { | |
607 if (! (stack.contains ("file") && stack.contains ("name") | |
608 && stack.contains ("line"))) | |
609 error ("rethrow: STACK struct must contain the fields 'file', 'name', and 'line'"); | |
610 | |
611 if (! stack.contains ("column")) | |
612 { | |
613 octave_map new_stack = stack; | |
614 | |
615 new_stack.setfield ("column", Cell (octave_value (-1))); | |
616 | |
617 ee.set_stack_info (make_stack_frame_list (new_stack)); | |
618 } | |
619 else | |
620 ee.set_stack_info (make_stack_frame_list (stack)); | |
621 } | |
622 | |
623 throw_error (ee); | |
624 } | |
625 | |
626 void error_system::vpanic (const char *fmt, va_list args) | |
627 { | |
628 // Is there any point in trying to write the panic message to the | |
629 // diary? | |
630 | |
631 std::cerr << "panic: " << format_message (fmt, args) << std::endl; | |
632 | |
633 abort (); | |
634 } | |
635 | |
636 void error_system::panic (const char *fmt, ...) | |
637 { | |
638 va_list args; | |
639 va_start (args, fmt); | |
640 vpanic (fmt, args); | |
641 va_end (args); | |
642 } | |
643 | |
644 octave_scalar_map error_system::warning_query (const std::string& id_arg) | |
645 { | |
646 octave_scalar_map retval; | |
647 | |
648 std::string id = id_arg; | |
649 | |
650 if (id == "last") | |
651 id = last_warning_id (); | |
652 | |
653 octave_map opts = warning_options (); | |
654 | |
655 Cell ident = opts.contents ("identifier"); | |
656 Cell state = opts.contents ("state"); | |
657 | |
658 octave_idx_type nel = ident.numel (); | |
659 | |
660 panic_if (nel == 0); | |
661 | |
662 bool found = false; | |
663 | |
664 std::string val; | |
665 | |
666 for (octave_idx_type i = 0; i < nel; i++) | |
667 { | |
668 if (ident(i).string_value () == id) | |
669 { | |
670 val = state(i).string_value (); | |
671 found = true; | |
672 break; | |
673 } | |
674 } | |
675 | |
676 if (! found) | |
677 { | |
678 for (octave_idx_type i = 0; i < nel; i++) | |
679 { | |
680 if (ident(i).string_value () == "all") | |
681 { | |
682 val = state(i).string_value (); | |
683 found = true; | |
464 break; | 684 break; |
465 } | 685 } |
466 } | 686 } |
467 | 687 } |
468 // If "all" is not present, assume warnings are enabled. | 688 |
469 if (all_state == -1) | 689 // The warning state "all" is always supposed to remain in the list, |
470 all_state = 1; | 690 // so we should always find a state, either explicitly or by using the |
471 | 691 // state for "all". |
472 if (all_state == 0) | 692 panic_unless (found); |
473 { | 693 |
474 if (id_state >= 0) | 694 retval.assign ("identifier", id); |
475 retval = id_state; | 695 retval.assign ("state", val); |
476 } | 696 |
477 else if (all_state == 1) | 697 return retval; |
478 { | 698 } |
479 if (id_state == 0 || id_state == 2) | 699 |
480 retval = id_state; | 700 std::string error_system::default_warning_state (void) |
481 else | 701 { |
482 retval = all_state; | 702 std::string retval = "on"; |
483 } | 703 |
484 else if (all_state == 2) | 704 octave_map opts = warning_options (); |
485 { | 705 |
486 if (id_state == 0) | 706 Cell ident = opts.contents ("identifier"); |
487 retval= id_state; | 707 Cell state = opts.contents ("state"); |
488 else | 708 |
489 retval = all_state; | 709 octave_idx_type nel = ident.numel (); |
490 } | 710 |
491 | 711 for (octave_idx_type i = 0; i < nel; i++) |
492 return retval; | 712 { |
493 } | 713 if (ident(i).string_value () == "all") |
494 | 714 { |
495 void error_system::vusage (const char *id, const char *fmt, va_list args) | 715 retval = state(i).string_value (); |
496 { | 716 break; |
497 std::string str_id = id ? id : ""; | 717 } |
498 std::string message = format_message (fmt, args); | 718 } |
499 | 719 |
500 throw_error ("usage", str_id, message); | 720 return retval; |
501 } | 721 } |
502 | 722 |
503 void error_system::vwarning (const char *name, const char *id, | 723 void error_system::display_warning_options (std::ostream& os) |
504 const char *fmt, va_list args) | 724 { |
505 { | 725 octave_map opts = warning_options (); |
506 flush_stdout (); | 726 |
507 | 727 Cell ident = opts.contents ("identifier"); |
508 std::string base_msg = format_message (fmt, args); | 728 Cell state = opts.contents ("state"); |
509 std::string msg_string; | 729 |
510 | 730 octave_idx_type nel = ident.numel (); |
511 if (name) | 731 |
512 msg_string = std::string (name) + ": "; | 732 std::string all_state = default_warning_state (); |
513 | 733 |
514 msg_string += base_msg; | 734 if (all_state == "on") |
515 | 735 os << "By default, warnings are enabled."; |
516 bool fmt_suppresses_backtrace = false; | 736 else if (all_state == "off") |
517 std::size_t fmt_len = (fmt ? strlen (fmt) : 0); | 737 os << "By default, warnings are disabled."; |
518 fmt_suppresses_backtrace = (fmt_len > 0 && fmt[fmt_len-1] == '\n'); | 738 else if (all_state == "error") |
519 | 739 os << "By default, warnings are treated as errors."; |
520 if (! fmt_suppresses_backtrace) | 740 else |
521 msg_string += '\n'; | 741 panic_impossible (); |
522 | 742 |
523 last_warning_id (id); | 743 if (nel > 1) |
524 last_warning_message (base_msg); | 744 { |
525 | 745 os << "\n"; |
526 if (discard_warning_messages ()) | 746 os << "Non-default warning states are:\n\n"; |
527 return; | 747 os << " State Warning ID\n"; |
528 | 748 } |
529 tree_evaluator& tw = m_interpreter.get_evaluator (); | 749 |
530 | 750 // The state for "all" is always supposed to be first in the list. |
531 bool in_user_code = tw.in_user_code (); | 751 |
532 | 752 for (octave_idx_type i = 1; i < nel; i++) |
533 if (! quiet_warning ()) | 753 { |
534 { | 754 std::string tid = ident(i).string_value (); |
535 octave_diary << msg_string; | 755 std::string tst = state(i).string_value (); |
536 std::cerr << msg_string; | 756 |
537 | 757 os << std::setw (7) << tst << " " << tid << "\n"; |
538 if (! fmt_suppresses_backtrace && in_user_code | 758 } |
539 && backtrace_on_warning () | 759 |
540 && ! discard_warning_messages ()) | 760 os << std::endl; |
541 { | 761 } |
542 std::string bt_msg = tw.backtrace_message (); | 762 |
543 | 763 void error_system::set_warning_option (const std::string& state, |
544 if (! bt_msg.empty ()) | 764 const std::string& ident) |
545 bt_msg = "warning: called from\n" + bt_msg; | 765 { |
546 | 766 std::string all_state = default_warning_state (); |
547 octave_diary << bt_msg << std::endl; | 767 |
548 std::cerr << bt_msg << std::endl; | 768 if (state != "on" && state != "off" && state != "error") |
549 } | 769 error ("invalid warning state: %s", state.c_str ()); |
550 } | 770 |
551 | 771 octave_map opts = warning_options (); |
552 bp_table& bptab = tw.get_bp_table (); | 772 |
553 | 773 Cell tid = opts.contents ("identifier"); |
554 if ((m_interpreter.interactive () | 774 Cell tst = opts.contents ("state"); |
555 || application::forced_interactive ()) | 775 |
556 && debug_on_warning () && in_user_code && bptab.debug_on_warn (id)) | 776 octave_idx_type nel = tid.numel (); |
557 { | 777 |
558 unwind_protect_var<bool> restore_var (m_debug_on_warning, false); | 778 for (octave_idx_type i = 0; i < nel; i++) |
559 | 779 { |
560 tw.enter_debugger (); | 780 if (tid(i).string_value () == ident) |
561 } | 781 { |
562 } | 782 // We found it in the current list of options. If the state |
563 | 783 // for "all" is same as arg1, we can simply remove the item |
564 void error_system::error_1 (execution_exception& ee, const char *id, | 784 // from the list. |
565 const char *fmt, va_list args) | 785 |
566 { | 786 if (state == all_state && ident != "all") |
567 ee.set_identifier (id); | 787 { |
568 ee.set_message (format_message (fmt, args)); | 788 for (i = i + 1; i < nel; i++) |
569 | 789 { |
570 throw_error (ee); | 790 tid(i-1) = tid(i); |
571 } | 791 tst(i-1) = tst(i); |
572 | 792 } |
573 void error_system::error_1 (const char *id, const char *fmt, | 793 |
574 va_list args) | 794 tid.resize (dim_vector (1, nel-1)); |
575 { | 795 tst.resize (dim_vector (1, nel-1)); |
576 std::string message = format_message (fmt, args); | 796 } |
577 | 797 else |
578 std::list<frame_info> stack_info; | 798 tst(i) = state; |
579 | 799 |
580 throw_error ("error", id, message); | 800 opts.clear (); |
581 } | 801 |
582 | 802 opts.assign ("identifier", tid); |
583 void error_system::vwarning (const char *id, const char *fmt, va_list args) | 803 opts.assign ("state", tst); |
584 { | 804 |
585 int warn_opt = warning_enabled (id); | 805 warning_options (opts); |
586 | 806 |
587 if (warn_opt == 2) | 807 return; |
588 { | 808 } |
589 // Handle this warning as an error. | 809 } |
590 | 810 |
591 error_1 (id, fmt, args); | 811 // The option wasn't already in the list. Append it. |
592 } | 812 |
593 else if (warn_opt == 1) | 813 tid.resize (dim_vector (1, nel+1)); |
594 vwarning ("warning", id, fmt, args); | 814 tst.resize (dim_vector (1, nel+1)); |
595 } | 815 |
596 | 816 tid(nel) = ident; |
597 void error_system::rethrow_error (const std::string& id, | 817 tst(nel) = state; |
598 const std::string& msg, | 818 |
599 const octave_map& stack) | 819 opts.clear (); |
600 { | 820 |
601 std::list<frame_info> stack_info; | 821 opts.assign ("identifier", tid); |
602 | 822 opts.assign ("state", tst); |
603 execution_exception ee ("error", id, msg, stack_info); | 823 |
604 | 824 warning_options (opts); |
605 if (! stack.isempty ()) | 825 } |
606 { | 826 |
607 if (! (stack.contains ("file") && stack.contains ("name") | 827 void error_system::disable_warning (const std::string& id) |
608 && stack.contains ("line"))) | 828 { |
609 error ("rethrow: STACK struct must contain the fields 'file', 'name', and 'line'"); | 829 set_warning_option ("off", id); |
610 | 830 } |
611 if (! stack.contains ("column")) | 831 |
612 { | 832 void error_system::initialize_default_warning_state (void) |
613 octave_map new_stack = stack; | 833 { |
614 | 834 warning_options (init_warning_options ("on")); |
615 new_stack.setfield ("column", Cell (octave_value (-1))); | 835 |
616 | 836 // Most people will want to have the following disabled. |
617 ee.set_stack_info (make_stack_frame_list (new_stack)); | 837 |
618 } | 838 disable_warning ("Octave:array-as-logical"); |
619 else | 839 disable_warning ("Octave:array-to-scalar"); |
620 ee.set_stack_info (make_stack_frame_list (stack)); | 840 disable_warning ("Octave:array-to-vector"); |
621 } | 841 disable_warning ("Octave:imag-to-real"); |
622 | 842 disable_warning ("Octave:language-extension"); |
623 throw_error (ee); | 843 disable_warning ("Octave:missing-semicolon"); |
624 } | 844 disable_warning ("Octave:neg-dim-as-zero"); |
625 | 845 disable_warning ("Octave:separator-insert"); |
626 void error_system::vpanic (const char *fmt, va_list args) | 846 disable_warning ("Octave:single-quote-string"); |
627 { | 847 disable_warning ("Octave:str-to-num"); |
628 // Is there any point in trying to write the panic message to the | 848 disable_warning ("Octave:mixed-string-concat"); |
629 // diary? | 849 disable_warning ("Octave:variable-switch-label"); |
630 | 850 } |
631 std::cerr << "panic: " << format_message (fmt, args) << std::endl; | 851 |
632 | 852 void error_system::interpreter_try (unwind_protect& frame) |
633 abort (); | 853 { |
634 } | 854 frame.protect_var (m_debug_on_error); |
635 | 855 m_debug_on_error = false; |
636 void error_system::panic (const char *fmt, ...) | 856 |
637 { | 857 frame.protect_var (m_debug_on_warning); |
638 va_list args; | 858 m_debug_on_warning = false; |
639 va_start (args, fmt); | 859 |
640 vpanic (fmt, args); | 860 // Leave debug_on_caught as it was, so errors in try/catch are still |
641 va_end (args); | 861 // caught. |
642 } | 862 } |
643 | 863 |
644 octave_scalar_map error_system::warning_query (const std::string& id_arg) | 864 void error_system::throw_error (const std::string& err_type, |
645 { | 865 const std::string& id, |
646 octave_scalar_map retval; | 866 const std::string& message, |
647 | 867 const std::list<frame_info>& stack_info_arg) |
648 std::string id = id_arg; | 868 { |
649 | 869 std::list<frame_info> stack_info = stack_info_arg; |
650 if (id == "last") | 870 |
651 id = last_warning_id (); | 871 if (stack_info.empty ()) |
652 | 872 { |
653 octave_map opts = warning_options (); | 873 tree_evaluator& tw = m_interpreter.get_evaluator (); |
654 | 874 |
655 Cell ident = opts.contents ("identifier"); | 875 stack_info = tw.backtrace_info (); |
656 Cell state = opts.contents ("state"); | 876 |
657 | 877 // Print the error message only if it is different from the |
658 octave_idx_type nel = ident.numel (); | 878 // previous one; makes the output more concise and readable. |
659 | 879 |
660 panic_if (nel == 0); | 880 stack_info.unique (); |
661 | 881 } |
662 bool found = false; | 882 |
663 | 883 execution_exception ex (err_type, id, message, stack_info); |
664 std::string val; | 884 |
665 | 885 throw_error (ex); |
666 for (octave_idx_type i = 0; i < nel; i++) | 886 } |
667 { | 887 |
668 if (ident(i).string_value () == id) | 888 void error_system::throw_error (execution_exception& ex) |
669 { | 889 { |
670 val = state(i).string_value (); | 890 throw ex; |
671 found = true; | 891 } |
672 break; | 892 |
673 } | 893 void error_system::save_exception (const execution_exception& ee) |
674 } | 894 { |
675 | 895 last_error_id (ee.identifier ()); |
676 if (! found) | 896 std::string message = ee.message (); |
677 { | 897 std::string xmsg |
678 for (octave_idx_type i = 0; i < nel; i++) | 898 = (message.size () > 0 && message.back () == '\n' |
679 { | 899 ? message.substr (0, message.size () - 1) : message); |
680 if (ident(i).string_value () == "all") | 900 last_error_message (xmsg); |
681 { | 901 last_error_stack (make_stack_map (ee.stack_info ())); |
682 val = state(i).string_value (); | 902 } |
683 found = true; | 903 |
684 break; | 904 void error_system::display_exception (const execution_exception& ee) const |
685 } | 905 { |
686 } | 906 // FIXME: How should we handle beep_on_error? |
687 } | 907 |
688 | 908 ee.display (octave_diary); |
689 // The warning state "all" is always supposed to remain in the list, | 909 |
690 // so we should always find a state, either explicitly or by using the | 910 // FIXME: Handle display using an event manager message so that the |
691 // state for "all". | 911 // GUI or other client can receive error messages without needing to |
692 panic_unless (found); | 912 // capture them from std::cerr or some other stream. |
693 | 913 |
694 retval.assign ("identifier", id); | 914 event_manager& evmgr = m_interpreter.get_event_manager (); |
695 retval.assign ("state", val); | 915 |
696 | 916 evmgr.display_exception (ee, m_beep_on_error); |
697 return retval; | 917 } |
698 } | |
699 | |
700 std::string error_system::default_warning_state (void) | |
701 { | |
702 std::string retval = "on"; | |
703 | |
704 octave_map opts = warning_options (); | |
705 | |
706 Cell ident = opts.contents ("identifier"); | |
707 Cell state = opts.contents ("state"); | |
708 | |
709 octave_idx_type nel = ident.numel (); | |
710 | |
711 for (octave_idx_type i = 0; i < nel; i++) | |
712 { | |
713 if (ident(i).string_value () == "all") | |
714 { | |
715 retval = state(i).string_value (); | |
716 break; | |
717 } | |
718 } | |
719 | |
720 return retval; | |
721 } | |
722 | |
723 void error_system::display_warning_options (std::ostream& os) | |
724 { | |
725 octave_map opts = warning_options (); | |
726 | |
727 Cell ident = opts.contents ("identifier"); | |
728 Cell state = opts.contents ("state"); | |
729 | |
730 octave_idx_type nel = ident.numel (); | |
731 | |
732 std::string all_state = default_warning_state (); | |
733 | |
734 if (all_state == "on") | |
735 os << "By default, warnings are enabled."; | |
736 else if (all_state == "off") | |
737 os << "By default, warnings are disabled."; | |
738 else if (all_state == "error") | |
739 os << "By default, warnings are treated as errors."; | |
740 else | |
741 panic_impossible (); | |
742 | |
743 if (nel > 1) | |
744 { | |
745 os << "\n"; | |
746 os << "Non-default warning states are:\n\n"; | |
747 os << " State Warning ID\n"; | |
748 } | |
749 | |
750 // The state for "all" is always supposed to be first in the list. | |
751 | |
752 for (octave_idx_type i = 1; i < nel; i++) | |
753 { | |
754 std::string tid = ident(i).string_value (); | |
755 std::string tst = state(i).string_value (); | |
756 | |
757 os << std::setw (7) << tst << " " << tid << "\n"; | |
758 } | |
759 | |
760 os << std::endl; | |
761 } | |
762 | |
763 void error_system::set_warning_option (const std::string& state, | |
764 const std::string& ident) | |
765 { | |
766 std::string all_state = default_warning_state (); | |
767 | |
768 if (state != "on" && state != "off" && state != "error") | |
769 error ("invalid warning state: %s", state.c_str ()); | |
770 | |
771 octave_map opts = warning_options (); | |
772 | |
773 Cell tid = opts.contents ("identifier"); | |
774 Cell tst = opts.contents ("state"); | |
775 | |
776 octave_idx_type nel = tid.numel (); | |
777 | |
778 for (octave_idx_type i = 0; i < nel; i++) | |
779 { | |
780 if (tid(i).string_value () == ident) | |
781 { | |
782 // We found it in the current list of options. If the state | |
783 // for "all" is same as arg1, we can simply remove the item | |
784 // from the list. | |
785 | |
786 if (state == all_state && ident != "all") | |
787 { | |
788 for (i = i + 1; i < nel; i++) | |
789 { | |
790 tid(i-1) = tid(i); | |
791 tst(i-1) = tst(i); | |
792 } | |
793 | |
794 tid.resize (dim_vector (1, nel-1)); | |
795 tst.resize (dim_vector (1, nel-1)); | |
796 } | |
797 else | |
798 tst(i) = state; | |
799 | |
800 opts.clear (); | |
801 | |
802 opts.assign ("identifier", tid); | |
803 opts.assign ("state", tst); | |
804 | |
805 warning_options (opts); | |
806 | |
807 return; | |
808 } | |
809 } | |
810 | |
811 // The option wasn't already in the list. Append it. | |
812 | |
813 tid.resize (dim_vector (1, nel+1)); | |
814 tst.resize (dim_vector (1, nel+1)); | |
815 | |
816 tid(nel) = ident; | |
817 tst(nel) = state; | |
818 | |
819 opts.clear (); | |
820 | |
821 opts.assign ("identifier", tid); | |
822 opts.assign ("state", tst); | |
823 | |
824 warning_options (opts); | |
825 } | |
826 | |
827 void error_system::disable_warning (const std::string& id) | |
828 { | |
829 set_warning_option ("off", id); | |
830 } | |
831 | |
832 void error_system::initialize_default_warning_state (void) | |
833 { | |
834 warning_options (init_warning_options ("on")); | |
835 | |
836 // Most people will want to have the following disabled. | |
837 | |
838 disable_warning ("Octave:array-as-logical"); | |
839 disable_warning ("Octave:array-to-scalar"); | |
840 disable_warning ("Octave:array-to-vector"); | |
841 disable_warning ("Octave:imag-to-real"); | |
842 disable_warning ("Octave:language-extension"); | |
843 disable_warning ("Octave:missing-semicolon"); | |
844 disable_warning ("Octave:neg-dim-as-zero"); | |
845 disable_warning ("Octave:separator-insert"); | |
846 disable_warning ("Octave:single-quote-string"); | |
847 disable_warning ("Octave:str-to-num"); | |
848 disable_warning ("Octave:mixed-string-concat"); | |
849 disable_warning ("Octave:variable-switch-label"); | |
850 } | |
851 | |
852 void error_system::interpreter_try (unwind_protect& frame) | |
853 { | |
854 frame.protect_var (m_debug_on_error); | |
855 m_debug_on_error = false; | |
856 | |
857 frame.protect_var (m_debug_on_warning); | |
858 m_debug_on_warning = false; | |
859 | |
860 // Leave debug_on_caught as it was, so errors in try/catch are still | |
861 // caught. | |
862 } | |
863 | |
864 void error_system::throw_error (const std::string& err_type, | |
865 const std::string& id, | |
866 const std::string& message, | |
867 const std::list<frame_info>& stack_info_arg) | |
868 { | |
869 std::list<frame_info> stack_info = stack_info_arg; | |
870 | |
871 if (stack_info.empty ()) | |
872 { | |
873 tree_evaluator& tw = m_interpreter.get_evaluator (); | |
874 | |
875 stack_info = tw.backtrace_info (); | |
876 | |
877 // Print the error message only if it is different from the | |
878 // previous one; makes the output more concise and readable. | |
879 | |
880 stack_info.unique (); | |
881 } | |
882 | |
883 execution_exception ex (err_type, id, message, stack_info); | |
884 | |
885 throw_error (ex); | |
886 } | |
887 | |
888 void error_system::throw_error (execution_exception& ex) | |
889 { | |
890 throw ex; | |
891 } | |
892 | |
893 void error_system::save_exception (const execution_exception& ee) | |
894 { | |
895 last_error_id (ee.identifier ()); | |
896 std::string message = ee.message (); | |
897 std::string xmsg | |
898 = (message.size () > 0 && message.back () == '\n' | |
899 ? message.substr (0, message.size () - 1) : message); | |
900 last_error_message (xmsg); | |
901 last_error_stack (make_stack_map (ee.stack_info ())); | |
902 } | |
903 | |
904 void error_system::display_exception (const execution_exception& ee) const | |
905 { | |
906 // FIXME: How should we handle beep_on_error? | |
907 | |
908 ee.display (octave_diary); | |
909 | |
910 // FIXME: Handle display using an event manager message so that the | |
911 // GUI or other client can receive error messages without needing to | |
912 // capture them from std::cerr or some other stream. | |
913 | |
914 event_manager& evmgr = m_interpreter.get_event_manager (); | |
915 | |
916 evmgr.display_exception (ee, m_beep_on_error); | |
917 } | |
918 | 918 |
919 OCTAVE_END_NAMESPACE(octave) | 919 OCTAVE_END_NAMESPACE(octave) |
920 | 920 |
921 void | 921 void |
922 vmessage (const char *name, const char *fmt, va_list args) | 922 vmessage (const char *name, const char *fmt, va_list args) |
1681 else | 1681 else |
1682 { | 1682 { |
1683 octave_scalar_map tmp = es.warning_query (arg2); | 1683 octave_scalar_map tmp = es.warning_query (arg2); |
1684 | 1684 |
1685 octave_stdout << '"' << arg2 << R"(" warning state is ")" << | 1685 octave_stdout << '"' << arg2 << R"(" warning state is ")" << |
1686 tmp.getfield ("state").string_value () << | 1686 tmp.getfield ("state").string_value () << |
1687 "\"\n"; | 1687 "\"\n"; |
1688 } | 1688 } |
1689 } | 1689 } |
1690 | 1690 |
1691 done = true; | 1691 done = true; |
1692 } | 1692 } |