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;
   };
 }