# HG changeset patch
# User Petter Tomner <tomner@kth.se>
# Date 1641474017 -3600
#      Thu Jan 06 14:00:17 2022 +0100
# Node ID 8cf8d74c46c7387bd1b038cf78fc32155c5ff181
# Parent  44e1d1e9dd61379850b48d6eafda4012d9302de7
WIP tree_statement -> tree_statement_cmd and tree_statement_expression

diff -r 44e1d1e9dd61 -r 8cf8d74c46c7 libinterp/parse-tree/oct-parse.yy
--- a/libinterp/parse-tree/oct-parse.yy	Wed Jan 05 22:43:51 2022 +0100
+++ b/libinterp/parse-tree/oct-parse.yy	Thu Jan 06 14:00:17 2022 +0100
@@ -5377,13 +5377,26 @@
   }
 
   // Finish building a statement.
-  template <typename T>
   tree_statement *
-  base_parser::make_statement (T *arg)
+  base_parser::make_statement (tree_expression *arg)
   {
     comment_list *comment = m_lexer.get_comment ();
 
-    return new tree_statement (arg, comment);
+    if (!arg)
+      return new tree_statement_null (comment);
+
+    return new tree_statement_expression (arg, comment);
+  }
+
+  tree_statement *
+  base_parser::make_statement (tree_command *arg)
+  {
+    comment_list *comment = m_lexer.get_comment ();
+
+    if (!arg)
+      return new tree_statement_null (comment);
+
+    return new tree_statement_cmd (arg, comment);
   }
 
   tree_statement_list *
diff -r 44e1d1e9dd61 -r 8cf8d74c46c7 libinterp/parse-tree/parse.h
--- a/libinterp/parse-tree/parse.h	Wed Jan 05 22:43:51 2022 +0100
+++ b/libinterp/parse-tree/parse.h	Thu Jan 06 14:00:17 2022 +0100
@@ -659,8 +659,11 @@
     set_stmt_print_flag (tree_statement_list *, char, bool);
 
     // Finish building a statement.
-    template <typename T>
-    OCTINTERP_API tree_statement * make_statement (T *arg);
+    OCTINTERP_API tree_statement *
+    make_statement (tree_expression *arg);
+
+    OCTINTERP_API tree_statement *
+    make_statement (tree_command *arg);
 
     // Create a statement list.
     OCTINTERP_API tree_statement_list *
diff -r 44e1d1e9dd61 -r 8cf8d74c46c7 libinterp/parse-tree/pt-bp.cc
--- a/libinterp/parse-tree/pt-bp.cc	Wed Jan 05 22:43:51 2022 +0100
+++ b/libinterp/parse-tree/pt-bp.cc	Thu Jan 06 14:00:17 2022 +0100
@@ -309,6 +309,20 @@
   }
 
   void
+  tree_breakpoint::visit_statement_expression (tree_statement_expression &stmt)
+  {
+    if (stmt.line () >= m_line)
+          take_action (stmt);
+  }
+
+  void
+  tree_breakpoint::visit_statement_null (tree_statement_null &stmt)
+  {
+    if (stmt.line () >= m_line)
+          take_action (stmt);
+  }
+
+  void
   tree_breakpoint::visit_statement (tree_statement& stmt)
   {
     if (stmt.is_command ())
@@ -324,6 +338,22 @@
       }
   }
 
+  void
+  tree_breakpoint::visit_statement_cmd (tree_statement_cmd& stmt)
+  {
+    if (stmt.is_command ())
+      {
+        tree_command *cmd = stmt.command ();
+
+        cmd->accept (*this);
+      }
+    else
+      {
+        if (stmt.line () >= m_line)
+          take_action (stmt);
+      }
+  }
+
   // Called by
   //   tree_statement_list::set_breakpoint (int line, std::string& condition)
   // with <lst> consisting of a user function in which to set a breakpoint.
diff -r 44e1d1e9dd61 -r 8cf8d74c46c7 libinterp/parse-tree/pt-bp.h
--- a/libinterp/parse-tree/pt-bp.h	Wed Jan 05 22:43:51 2022 +0100
+++ b/libinterp/parse-tree/pt-bp.h	Thu Jan 06 14:00:17 2022 +0100
@@ -135,6 +135,12 @@
 
     void visit_statement (tree_statement&);
 
+    void visit_statement_null (tree_statement_null&);
+
+    void visit_statement_cmd (tree_statement_cmd&);
+
+    void visit_statement_expression (tree_statement_expression&);
+
     void visit_statement_list (tree_statement_list&);
 
     void visit_switch_case (tree_switch_case&);
diff -r 44e1d1e9dd61 -r 8cf8d74c46c7 libinterp/parse-tree/pt-eval.cc
--- a/libinterp/parse-tree/pt-eval.cc	Wed Jan 05 22:43:51 2022 +0100
+++ b/libinterp/parse-tree/pt-eval.cc	Thu Jan 06 14:00:17 2022 +0100
@@ -3720,116 +3720,182 @@
   }
 
   void
-  tree_evaluator::visit_statement (tree_statement& stmt)
+  tree_evaluator::visit_statement_null (tree_statement_null&)
+  {
+    // Do nothing
+  }
+
+  void
+  tree_evaluator::visit_statement_cmd (tree_statement_cmd &stmt)
   {
     tree_command *cmd = stmt.command ();
-    tree_expression *expr = stmt.expression ();
-
-    if (cmd || expr)
+
+    if (! (in_debug_repl ()
+           && m_call_stack.current_frame () == m_debug_frame))
+      m_call_stack.set_location (stmt.line (), stmt.column ());
+
+    try
+      {
+        unwind_protect_var<const tiny_vector<octave_lvalue> *>
+          upv (m_lvalue_vec, nullptr);
+
+        cmd->accept (*this);
+
+      }
+    catch (const std::bad_alloc&)
+      {
+        // FIXME: We want to use error_with_id here so that give users
+        // control over this error message but error_with_id will
+        // require some memory allocations.  Is there anything we can
+        // do to make those more likely to succeed?
+
+        error_with_id ("Octave:bad-alloc",
+                       "out of memory or dimension too large for Octave's "
+                       "index type");
+      }
+    catch (const interrupt_exception&)
+      {
+        // If we are debugging, then continue with next statement.
+        // Otherwise, jump out of here.
+
+        if (m_debug_mode)
+          m_interpreter.recover_from_exception ();
+        else
+          throw;
+      }
+    catch (const execution_exception& ee)
       {
-        if (! (in_debug_repl ()
-               && m_call_stack.current_frame () == m_debug_frame))
-          m_call_stack.set_location (stmt.line (), stmt.column ());
-
-        try
+        error_system& es = m_interpreter.get_error_system ();
+
+        if ((m_interpreter.interactive ()
+             || application::forced_interactive ())
+            && ((es.debug_on_error ()
+                 && m_bp_table.debug_on_err (es.last_error_id ()))
+                || (es.debug_on_caught ()
+                    && m_bp_table.debug_on_caught (es.last_error_id ())))
+            && in_user_code ())
           {
-            if (cmd)
-              {
-                unwind_protect_var<const tiny_vector<octave_lvalue> *>
-                  upv (m_lvalue_vec, nullptr);
-
-                cmd->accept (*this);
-              }
+            es.save_exception (ee);
+            es.display_exception (ee);
+
+            enter_debugger ();
+
+            // It doesn't make sense to continue execution after an
+            // error occurs so force the debugger to quit all debug
+            // levels and return the the top prompt.
+
+            throw quit_debug_exception (true);
+          }
+        else
+          throw;
+      }
+  }
+
+  void
+  tree_evaluator::visit_statement_expression (tree_statement_expression &stmt)
+  {
+    tree_expression *expr = stmt.expression ();
+
+    if (! (in_debug_repl ()
+           && m_call_stack.current_frame () == m_debug_frame))
+      m_call_stack.set_location (stmt.line (), stmt.column ());
+
+    try
+      {
+        if (m_echo_state)
+          {
+            int line = stmt.line ();
+            if (line < 0)
+              line = 1;
+            echo_code (line);
+            m_echo_file_pos = line + 1;
+          }
+
+        if (m_debug_mode)
+          do_breakpoint (expr->is_active_breakpoint (*this));
+
+        // FIXME: maybe all of this should be packaged in
+        // one virtual function that returns a flag saying whether
+        // or not the expression will take care of binding ans and
+        // printing the result.
+
+        // FIXME: it seems that we should just have to
+        // evaluate the expression and that should take care of
+        // everything, binding ans as necessary?
+
+        octave_value tmp_result = expr->evaluate (*this, 0);
+
+        if (tmp_result.is_defined ())
+          {
+            bool do_bind_ans = false;
+
+            if (expr->is_identifier ())
+              do_bind_ans = ! is_variable (expr);
             else
-              {
-                if (m_echo_state)
-                  {
-                    int line = stmt.line ();
-                    if (line < 0)
-                      line = 1;
-                    echo_code (line);
-                    m_echo_file_pos = line + 1;
-                  }
-
-                if (m_debug_mode)
-                  do_breakpoint (expr->is_active_breakpoint (*this));
-
-                // FIXME: maybe all of this should be packaged in
-                // one virtual function that returns a flag saying whether
-                // or not the expression will take care of binding ans and
-                // printing the result.
-
-                // FIXME: it seems that we should just have to
-                // evaluate the expression and that should take care of
-                // everything, binding ans as necessary?
-
-                octave_value tmp_result = expr->evaluate (*this, 0);
-
-                if (tmp_result.is_defined ())
-                  {
-                    bool do_bind_ans = false;
-
-                    if (expr->is_identifier ())
-                      do_bind_ans = ! is_variable (expr);
-                    else
-                      do_bind_ans = ! expr->is_assignment_expression ();
-
-                    if (do_bind_ans)
-                      bind_ans (tmp_result, expr->print_result ()
-                                && statement_printing_enabled ());
-                  }
-              }
+              do_bind_ans = ! expr->is_assignment_expression ();
+
+            if (do_bind_ans)
+              bind_ans (tmp_result, expr->print_result ()
+                        && statement_printing_enabled ());
           }
-        catch (const std::bad_alloc&)
+
+      }
+    catch (const std::bad_alloc&)
+      {
+        // FIXME: We want to use error_with_id here so that give users
+        // control over this error message but error_with_id will
+        // require some memory allocations.  Is there anything we can
+        // do to make those more likely to succeed?
+
+        error_with_id ("Octave:bad-alloc",
+                       "out of memory or dimension too large for Octave's "
+                       "index type");
+      }
+    catch (const interrupt_exception&)
+      {
+        // If we are debugging, then continue with next statement.
+        // Otherwise, jump out of here.
+
+        if (m_debug_mode)
+          m_interpreter.recover_from_exception ();
+        else
+          throw;
+      }
+    catch (const execution_exception& ee)
+      {
+        error_system& es = m_interpreter.get_error_system ();
+
+        if ((m_interpreter.interactive ()
+             || application::forced_interactive ())
+            && ((es.debug_on_error ()
+                 && m_bp_table.debug_on_err (es.last_error_id ()))
+                || (es.debug_on_caught ()
+                    && m_bp_table.debug_on_caught (es.last_error_id ())))
+            && in_user_code ())
           {
-            // FIXME: We want to use error_with_id here so that give users
-            // control over this error message but error_with_id will
-            // require some memory allocations.  Is there anything we can
-            // do to make those more likely to succeed?
-
-            error_with_id ("Octave:bad-alloc",
-                           "out of memory or dimension too large for Octave's index type");
-          }
-        catch (const interrupt_exception&)
-          {
-            // If we are debugging, then continue with next statement.
-            // Otherwise, jump out of here.
-
-            if (m_debug_mode)
-              m_interpreter.recover_from_exception ();
-            else
-              throw;
+            es.save_exception (ee);
+            es.display_exception (ee);
+
+            enter_debugger ();
+
+            // It doesn't make sense to continue execution after an
+            // error occurs so force the debugger to quit all debug
+            // levels and return the the top prompt.
+
+            throw quit_debug_exception (true);
           }
-        catch (const execution_exception& ee)
-          {
-            error_system& es = m_interpreter.get_error_system ();
-
-            if ((m_interpreter.interactive ()
-                 || application::forced_interactive ())
-                && ((es.debug_on_error ()
-                     && m_bp_table.debug_on_err (es.last_error_id ()))
-                    || (es.debug_on_caught ()
-                        && m_bp_table.debug_on_caught (es.last_error_id ())))
-                && in_user_code ())
-              {
-                es.save_exception (ee);
-                es.display_exception (ee);
-
-                enter_debugger ();
-
-                // It doesn't make sense to continue execution after an
-                // error occurs so force the debugger to quit all debug
-                // levels and return the the top prompt.
-
-                throw quit_debug_exception (true);
-              }
-            else
-              throw;
-          }
+        else
+          throw;
       }
   }
 
   void
+  tree_evaluator::visit_statement (tree_statement&)
+  {
+    panic_impossible();
+  }
+
+  void
   tree_evaluator::visit_statement_list (tree_statement_list& lst)
   {
     // FIXME: commented out along with else clause below.
diff -r 44e1d1e9dd61 -r 8cf8d74c46c7 libinterp/parse-tree/pt-eval.h
--- a/libinterp/parse-tree/pt-eval.h	Wed Jan 05 22:43:51 2022 +0100
+++ b/libinterp/parse-tree/pt-eval.h	Thu Jan 06 14:00:17 2022 +0100
@@ -299,6 +299,12 @@
 
     void visit_statement (tree_statement&);
 
+    void visit_statement_null (tree_statement_null&);
+
+    void visit_statement_cmd (tree_statement_cmd&);
+
+    void visit_statement_expression (tree_statement_expression&);
+
     void visit_statement_list (tree_statement_list&);
 
     void visit_switch_case (tree_switch_case&);
diff -r 44e1d1e9dd61 -r 8cf8d74c46c7 libinterp/parse-tree/pt-fcn-handle.cc
--- a/libinterp/parse-tree/pt-fcn-handle.cc	Wed Jan 05 22:43:51 2022 +0100
+++ b/libinterp/parse-tree/pt-fcn-handle.cc	Thu Jan 06 14:00:17 2022 +0100
@@ -123,7 +123,8 @@
     if (m_expression)
       {
         tree_expression *expr_dup = m_expression->dup (new_scope);
-        tree_statement *stmt = new tree_statement (expr_dup, nullptr);
+        tree_statement *stmt = new tree_statement_expression (expr_dup,
+                                                              nullptr);
         stmt_list = new tree_statement_list (stmt);
       }
 
diff -r 44e1d1e9dd61 -r 8cf8d74c46c7 libinterp/parse-tree/pt-stmt.h
--- a/libinterp/parse-tree/pt-stmt.h	Wed Jan 05 22:43:51 2022 +0100
+++ b/libinterp/parse-tree/pt-stmt.h	Thu Jan 06 14:00:17 2022 +0100
@@ -23,6 +23,7 @@
 //
 ////////////////////////////////////////////////////////////////////////
 
+#include "error.h"
 #if ! defined (octave_pt_stmt_h)
 #define octave_pt_stmt_h 1
 
@@ -51,11 +52,15 @@
 
   class tree_statement : public tree
   {
-  public:
+
+    friend class tree_statement_cmd;
+    friend class tree_statement_null;
+    friend class tree_statement_expression;
 
-    tree_statement (void)
+  private:
+    tree_statement (comment_list *cl)
       : m_command (nullptr), m_expression (nullptr),
-        m_comment_list (nullptr) { }
+        m_comment_list (cl) { }
 
     tree_statement (tree_command *c, comment_list *cl)
       : m_command (c), m_expression (nullptr), m_comment_list (cl) { }
@@ -63,6 +68,7 @@
     tree_statement (tree_expression *e, comment_list *cl)
       : m_command (nullptr), m_expression (e), m_comment_list (cl) { }
 
+  public:
     // No copying!
 
     tree_statement (const tree_statement&) = delete;
@@ -138,6 +144,52 @@
     comment_list *m_comment_list;
   };
 
+  class tree_statement_cmd : public tree_statement
+  {
+  public:
+    tree_statement_cmd (tree_command *c, comment_list *cl)
+      : tree_statement (c, cl)
+    {
+      if (!c)
+        panic_impossible();
+    }
+
+    void accept (tree_walker& tw)
+    {
+      tw.visit_statement_cmd (*this);
+    }
+  };
+
+  class tree_statement_expression : public tree_statement
+  {
+  public:
+    tree_statement_expression (tree_expression *c, comment_list *cl)
+      : tree_statement (c, cl)
+    {
+      if (!c)
+        panic_impossible();
+    }
+
+    void accept (tree_walker& tw)
+    {
+      tw.visit_statement_expression (*this);
+    }
+
+  };
+
+  class tree_statement_null : public tree_statement
+  {
+  public:
+    tree_statement_null (comment_list *cl)
+      : tree_statement (cl) {}
+
+    void accept (tree_walker& tw)
+    {
+      tw.visit_statement_null (*this);
+    }
+
+  };
+
   // A list of statements to evaluate.
 
   class tree_statement_list : public base_list<tree_statement *>
diff -r 44e1d1e9dd61 -r 8cf8d74c46c7 libinterp/parse-tree/pt-walk.cc
--- a/libinterp/parse-tree/pt-walk.cc	Wed Jan 05 22:43:51 2022 +0100
+++ b/libinterp/parse-tree/pt-walk.cc	Thu Jan 06 14:00:17 2022 +0100
@@ -537,6 +537,29 @@
       }
   }
 
+
+  void tree_walker::visit_statement_null (tree_statement_null&)
+  {
+    // Do nothing
+  }
+
+  void tree_walker::visit_statement_cmd (tree_statement_cmd& stmt)
+  {
+    tree_command *cmd = stmt.command ();
+
+    if (cmd)
+      cmd->accept (*this);
+  }
+
+  void tree_walker::visit_statement_expression (tree_statement_expression& stmt)
+  {
+    tree_expression *expr = stmt.expression ();
+
+    if (expr)
+      expr->accept (*this);
+
+  }
+
   void tree_walker::visit_statement_list (tree_statement_list& lst)
   {
     for (tree_statement *elt : lst)
diff -r 44e1d1e9dd61 -r 8cf8d74c46c7 libinterp/parse-tree/pt-walk.h
--- a/libinterp/parse-tree/pt-walk.h	Wed Jan 05 22:43:51 2022 +0100
+++ b/libinterp/parse-tree/pt-walk.h	Thu Jan 06 14:00:17 2022 +0100
@@ -81,6 +81,9 @@
   class tree_return_command;
   class tree_simple_assignment;
   class tree_statement;
+  class tree_statement_cmd;
+  class tree_statement_expression;
+  class tree_statement_null;
   class tree_statement_list;
   class tree_try_catch_command;
   class tree_unwind_protect_command;
@@ -209,6 +212,12 @@
 
     virtual void visit_statement (tree_statement&);
 
+    virtual void visit_statement_cmd (tree_statement_cmd&);
+
+    virtual void visit_statement_expression (tree_statement_expression&);
+
+    virtual void visit_statement_null (tree_statement_null&);
+
     virtual void visit_statement_list (tree_statement_list&);
 
     virtual void visit_try_catch_command (tree_try_catch_command&);
