Mercurial > octave
changeset 27282:49c60d16866f
improve dbquit and dbcont behavior
* pt-eval.h, pt-eval.cc (class quit_debug_exception): New class.
(tree_evaluator::m_in_top_level_repl): New data member.
(tree_evaluator::in_top_level_repl): New function.
(tree_evaluator::repl): Protect and set m_in_top_level_repl.
Catch quit_debug_exception.
(tree_evaluator::dbcont, tree_evaluator::dbquit): New functions.
(tree_evaluator::exit_debug_repl, tree_evaluator::abort_debug_repl,
tree_evaluator::in_debug_repl(bool)): Delete. Replace as needed with
calls to new dbquit or dbcont functions.
(debugger::execution_mode): New enum.
(debugger::m_exit_debug_repl, debugger::m_abort_debug_repl):
Delete data members and all uses.
(debugger::exit_debug_repl, debugger::abort_debug_repl,
debugger::in_debug_repl(bool)): Delete member functions and all uses.
(debugger::m_execution_mode): New data member.
(debugger::repl): Protect m_execution_mode. Check m_execution_mode,
m_level, and in_top_level_repl outside of loop to decide how to exit
current debugger repl. Catch quit_debug_exception in loop to pop to
previous debug level and rethrow to implement "quit all" action.
* debug.cc (Fdbcont): Call tree_evaluator::dbcont instead of
tree_evaluator::exit_debug_repl.
(Fdbquit): Call tree_evaluator::dbquit with optional flag to indicate
"all" option instead of calling tree_evaluator::abort_debug_repl or
tree_evaluator::exit_debug_repl.
author | John W. Eaton <jwe@octave.org> |
---|---|
date | Mon, 22 Jul 2019 18:56:31 -0400 |
parents | 0915fec3d3a9 |
children | 189ca5990c5d |
files | libinterp/corefcn/debug.cc libinterp/parse-tree/pt-eval.cc libinterp/parse-tree/pt-eval.h |
diffstat | 3 files changed, 106 insertions(+), 89 deletions(-) [+] |
line wrap: on
line diff
--- a/libinterp/corefcn/debug.cc Mon Jul 22 22:20:56 2019 +0200 +++ b/libinterp/corefcn/debug.cc Mon Jul 22 18:56:31 2019 -0400 @@ -1143,7 +1143,7 @@ Vtrack_line_num = true; - tw.exit_debug_repl (true); + tw.dbcont (); return ovl (); } @@ -1174,14 +1174,12 @@ = args(0).xstring_value ("dbquit: input argument must be a string"); if (arg == "all") - tw.abort_debug_repl (true); + tw.dbquit (true); else error ("dbquit: unrecognized argument '%s'", arg.c_str ()); } else - tw.exit_debug_repl (true); - - tw.debug_mode (false); + tw.dbquit (); return ovl (); }
--- a/libinterp/parse-tree/pt-eval.cc Mon Jul 22 22:20:56 2019 +0200 +++ b/libinterp/parse-tree/pt-eval.cc Mon Jul 22 18:56:31 2019 -0400 @@ -70,42 +70,57 @@ { // Normal evaluator. + class quit_debug_exception + { + public: + + quit_debug_exception (bool all = false) : m_all (all) { } + + quit_debug_exception (const quit_debug_exception&) = default; + + quit_debug_exception& operator = (const quit_debug_exception&) = default; + + ~quit_debug_exception (void) = default; + + bool all (void) const { return m_all; } + + private: + + bool m_all; + }; + class debugger { public: + enum execution_mode + { + EX_NORMAL = 0, + EX_CONTINUE = 1, + EX_QUIT = 2, + EX_QUIT_ALL = 3 + }; + debugger (interpreter& interp, size_t level) - : m_interpreter (interp), m_level (level), m_in_debug_repl (false), - m_exit_debug_repl (false), m_abort_debug_repl (false) + : m_interpreter (interp), m_level (level), m_debug_frame (0), + m_execution_mode (EX_NORMAL), m_in_debug_repl (false) { } void repl (const std::string& prompt = "debug> "); bool in_debug_repl (void) const { return m_in_debug_repl; } - bool in_debug_repl (bool flag) - { - bool val = m_in_debug_repl; - m_in_debug_repl = flag; - return val; - } - - bool exit_debug_repl (void) const { return m_exit_debug_repl; } - - bool exit_debug_repl (bool flag) + void dbcont (void) { - bool val = m_exit_debug_repl; - m_exit_debug_repl = flag; - return val; + m_execution_mode = EX_CONTINUE; } - bool abort_debug_repl (void) const { return m_abort_debug_repl; } - - bool abort_debug_repl (bool flag) + void dbquit (bool all = false) { - bool val = m_abort_debug_repl; - m_abort_debug_repl = flag; - return val; + if (all) + m_execution_mode = EX_QUIT_ALL; + else + m_execution_mode = EX_QUIT; } private: @@ -114,9 +129,8 @@ size_t m_level; size_t m_debug_frame; + execution_mode m_execution_mode; bool m_in_debug_repl; - bool m_exit_debug_repl; - bool m_abort_debug_repl; }; void debugger::repl (const std::string& prompt) @@ -124,6 +138,7 @@ unwind_protect frame; frame.protect_var (m_in_debug_repl); + frame.protect_var (m_execution_mode); m_in_debug_repl = true; @@ -236,11 +251,30 @@ while (m_in_debug_repl) { - if (m_exit_debug_repl || tw.dbstep_flag ()) + if (m_execution_mode == EX_CONTINUE || tw.dbstep_flag ()) break; - if (m_abort_debug_repl) - throw interrupt_exception (); + if (m_execution_mode == EX_QUIT) + { + // If there is no enclosing debug level or the top-level + // repl is not active, handle dbquit the same as dbcont. + + if (m_level > 0 || tw.in_top_level_repl ()) + throw quit_debug_exception (); + else + break; + } + + if (m_execution_mode == EX_QUIT_ALL) + { + // If the top-level repl is not active, handle "dbquit all" + // the same as dbcont. + + if (tw.in_top_level_repl ()) + throw quit_debug_exception (true); + else + break; + } try { @@ -278,9 +312,9 @@ octave_quit (); } } - catch (const execution_exception& e) + catch (const execution_exception& ee) { - std::string stack_trace = e.info (); + std::string stack_trace = ee.info (); if (! stack_trace.empty ()) std::cerr << stack_trace; @@ -288,6 +322,13 @@ // Ignore errors when in debugging mode; interpreter::recover_from_exception (); } + catch (const quit_debug_exception& qde) + { + if (qde.all ()) + throw; + + // Continue in this debug level. + } } } @@ -313,6 +354,12 @@ { try { + unwind_protect frame; + + frame.protect_var (m_in_top_level_repl); + + m_in_top_level_repl = true; + es.reset (); repl_parser.reset (); @@ -364,6 +411,10 @@ if (interactive) octave_stdout << "\n"; } + catch (const quit_debug_exception&) + { + m_interpreter.recover_from_exception (); + } catch (const index_exception& e) { m_interpreter.recover_from_exception (); @@ -1069,8 +1120,8 @@ void tree_evaluator::reset_debug_state (void) { - m_debug_mode - = (m_bp_table.have_breakpoints () || m_dbstep_flag != 0 || in_debug_repl ()); + m_debug_mode = (m_bp_table.have_breakpoints () || m_dbstep_flag != 0 + || in_debug_repl ()); } void @@ -3724,11 +3775,7 @@ // Act like dbcont. if (in_debug_repl () && m_call_stack.current_frame () == m_debug_frame) - { - m_dbstep_flag = 0; - - exit_debug_repl (true); - } + dbcont (); else if (m_statement_context == SC_FUNCTION || m_statement_context == SC_SCRIPT || m_in_loop_command) @@ -4913,40 +4960,16 @@ ? false : m_debugger_stack.top()->in_debug_repl ()); } - bool tree_evaluator::in_debug_repl (bool flag) + void tree_evaluator::dbcont (void) { if (! m_debugger_stack.empty ()) - error ("attempt to set in_debug_repl without debugger object"); - - return m_debugger_stack.top()->in_debug_repl (flag); - } - - bool tree_evaluator::exit_debug_repl (void) const - { - return (m_debugger_stack.empty () - ? false : m_debugger_stack.top()->exit_debug_repl (true)); - } - - bool tree_evaluator::exit_debug_repl (bool flag) - { - if (m_debugger_stack.empty ()) - error ("attempt to set exit_debug_repl without debugger object"); - - return m_debugger_stack.top()->exit_debug_repl (flag); - } - - bool tree_evaluator::abort_debug_repl (void) const - { - return (m_debugger_stack.empty () - ? false : m_debugger_stack.top()->abort_debug_repl ()); - } - - bool tree_evaluator::abort_debug_repl (bool flag) - { - if (m_debugger_stack.empty ()) - error ("attempt to set abort_debug_repl without debugger object"); - - return m_debugger_stack.top()->abort_debug_repl (flag); + m_debugger_stack.top()->dbcont (); + } + + void tree_evaluator::dbquit (bool all) + { + if (! m_debugger_stack.empty ()) + m_debugger_stack.top()->dbquit (all); } octave_value
--- a/libinterp/parse-tree/pt-eval.h Mon Jul 22 22:20:56 2019 +0200 +++ b/libinterp/parse-tree/pt-eval.h Mon Jul 22 18:56:31 2019 -0400 @@ -143,7 +143,7 @@ m_echo_files (), m_in_loop_command (false), m_breaking (0), m_continuing (0), m_returning (0), m_indexed_object (nullptr), m_index_position (0), - m_num_indices (0) + m_num_indices (0), m_in_top_level_repl (false) { } // No copying! @@ -664,15 +664,6 @@ return m_call_stack.current_frame (); } - bool debug_mode (void) const { return m_debug_mode; } - - bool debug_mode (bool flag) - { - bool val = m_debug_mode; - m_debug_mode = flag; - return val; - } - bool quiet_breakpoint_flag (void) const { return m_quiet_breakpoint_flag; } bool quiet_breakpoint_flag (bool flag) @@ -691,15 +682,15 @@ return val; } - // The following functions are provided for convenience and forward - // to the corresponding functions in the debugger class for the + // The following functions are provided for convenience. They + // call the corresponding functions in the debugger class for the // current debugger (if any). + bool in_debug_repl (void) const; - bool in_debug_repl (bool flag); - bool exit_debug_repl (void) const; - bool exit_debug_repl (bool flag); - bool abort_debug_repl (void) const; - bool abort_debug_repl (bool flag); + + void dbcont (void); + + void dbquit (bool all = false); octave_value PS4 (const octave_value_list& args, int nargout); @@ -721,6 +712,8 @@ int num_indices (void) const { return m_num_indices; } + bool in_top_level_repl (void) const { return m_in_top_level_repl; } + int breaking (void) const { return m_breaking; } int breaking (int n) @@ -919,6 +912,9 @@ const octave_value *m_indexed_object; int m_index_position; int m_num_indices; + + // TRUE if we are in the top level interactive read eval print loop. + bool m_in_top_level_repl; }; }