changeset 33573:1cfa8b20a07d bytecode-interpreter

maint: Merge default to bytecode-interpreter
author Arun Giridhar <arungiridhar@gmail.com>
date Sat, 11 May 2024 15:03:00 -0400
parents 9f0f7a898b73 (current diff) c0d79d64a1b8 (diff)
children e894b4443965
files etc/NEWS.9.md libinterp/parse-tree/pt-eval.cc
diffstat 10 files changed, 251 insertions(+), 23 deletions(-) [+]
line wrap: on
line diff
--- a/etc/NEWS.10.md	Fri May 10 17:57:29 2024 -0400
+++ b/etc/NEWS.10.md	Sat May 11 15:03:00 2024 -0400
@@ -31,6 +31,9 @@
 - The third output for `unique` is now correct when `stable` sort option is
   used.
 
+- Support setting breakpoints in `set` or `get` methods of `classdef`
+  properties (bug #65610).
+
 ### Graphical User Interface
 
 ### Graphics backend
--- a/etc/NEWS.9.md	Fri May 10 17:57:29 2024 -0400
+++ b/etc/NEWS.9.md	Sat May 11 15:03:00 2024 -0400
@@ -19,6 +19,13 @@
   states (bug #65595).
 - Fix segmentation fault when trying to set breakpoint in non-existent method
   of `classdef` class (bug #65610).
+- Improve default display of `classdef` properties (bug #62432).
+- Avoid crash with Qt6 6.7.0 (bug #65605).
+- `bar.m`: Catch input number validation error.
+- Prevent OOM crash or segmentation fault in `sort ()` when `dim` equals `Inf`
+  (bug #65712).
+- `legend.m`: Avoid setting more colors than coordinates for `patch` objects
+  (bug #65632).
 
 ### GUI
 
@@ -44,6 +51,10 @@
   summary.
 - Run test program for polymorphic allocators if possible instead of a simple
   build check.
+- Speed up BIST for the central part of `convn` with `'full'` shape.
+- Require Qt Widgets module when building the GUI (bug #65625).
+- `bug-53027.tst`: Delete temporary file after test is done (bug #53027).
+- Avoid build error with GCC 14 when targeting Windows.
 
 ### Documentation
 
@@ -56,6 +67,12 @@
 - Add application notes in `fminsearch`, `fminbnd`, `fminunc` indicating the
   preferred way to pass parameters is through anonymous functions.
 - Update remaining copyright statements to 2024.
+- Minor fix for `setappdata.m`.
+- Section "Assignment Expressions": Use `@emph` rather than `@i` macro for
+  better rendering in plaintext formats.
+- Section "Running Octave": Tell new users how to start Octave on their
+  computers.
+- `tsearch`: Add programming note about expected performance.
 
 ### Deprecated functions, properties, and operators
 
--- a/libinterp/corefcn/xnorm.cc	Fri May 10 17:57:29 2024 -0400
+++ b/libinterp/corefcn/xnorm.cc	Sat May 11 15:03:00 2024 -0400
@@ -51,7 +51,7 @@
     retval = octave_value (0);
   else if (isvector)
     {
-      if (isfloat & iscomplex)
+      if (isfloat && iscomplex)
         retval = octave::xnorm (x.float_complex_column_vector_value (),
                                 p.float_value ());
       else if (isfloat)
@@ -75,7 +75,7 @@
     }
   else
     {
-      if (isfloat & iscomplex)
+      if (isfloat && iscomplex)
         retval = octave::xnorm (x.float_complex_matrix_value (),
                                 p.float_value ());
       else if (isfloat)
@@ -115,7 +115,7 @@
     }
   else
     {
-      if (isfloat & iscomplex)
+      if (isfloat && iscomplex)
         retval = octave::xcolnorms (x.float_complex_matrix_value (),
                                     p.float_value ());
       else if (isfloat)
@@ -155,7 +155,7 @@
     }
   else
     {
-      if (isfloat & iscomplex)
+      if (isfloat && iscomplex)
         retval = octave::xrownorms (x.float_complex_matrix_value (),
                                     p.float_value ());
       else if (isfloat)
@@ -193,7 +193,7 @@
     }
   else
     {
-      if (isfloat & iscomplex)
+      if (isfloat && iscomplex)
         retval = octave::xfrobnorm (x.float_complex_matrix_value ());
       else if (isfloat)
         retval = octave::xfrobnorm (x.float_matrix_value ());
--- a/libinterp/octave-value/cdef-class.cc	Fri May 10 17:57:29 2024 -0400
+++ b/libinterp/octave-value/cdef-class.cc	Sat May 11 15:03:00 2024 -0400
@@ -721,27 +721,73 @@
       const octave_value& fcn = i->second.get_function ();
       octave_user_code *user_code = fcn.user_code_value ();
 
-      if (user_code == nullptr)
+      if (! user_code)
         continue;
 
-      octave_user_function* pfcn
-        = dynamic_cast<octave_user_function*> (user_code);
+      octave_user_function *pfcn
+        = dynamic_cast<octave_user_function *> (user_code);
 
-      if (pfcn == nullptr)
+      if (! pfcn)
         continue;
 
       octave::filepos end_pos = pfcn->end_pos ();
 
       int end_line = end_pos.line ();
 
-      if (line <= end_line && end_line <= closest_match_end_line && pfcn->is_defined ()
-          && pfcn->is_user_code ())
+      if (line <= end_line && end_line <= closest_match_end_line
+          && pfcn->is_defined () && pfcn->is_user_code ())
         {
           closest_match = fcn;
           closest_match_end_line = end_line;
         }
     }
 
+  // repeat the same for set and get methods of properties
+  for (auto i = m_property_map.cbegin (); i != m_property_map.cend (); ++i)
+    {
+      const octave_value& get_meth = i->second.get ("GetMethod");
+      if (get_meth.is_function_handle ())
+        {
+          octave_user_function *pfcn
+            = get_meth.user_function_value ();
+
+          if (! pfcn)
+            continue;
+
+          octave::filepos end_pos = pfcn->end_pos ();
+
+          int end_line = end_pos.line ();
+
+          if (line <= end_line && end_line <= closest_match_end_line
+              && pfcn->is_defined () && pfcn->is_user_code ())
+            {
+              closest_match = get_meth;
+              closest_match_end_line = end_line;
+            }
+        }
+
+      const octave_value& set_meth = i->second.get ("SetMethod");
+      if (set_meth.is_function_handle ())
+        {
+          octave_user_function *pfcn
+            = set_meth.user_function_value ();
+
+          if (! pfcn)
+            continue;
+
+          octave::filepos end_pos = pfcn->end_pos ();
+
+          int end_line = end_pos.line ();
+
+          if (line <= end_line && end_line <= closest_match_end_line
+              && pfcn->is_defined () && pfcn->is_user_code ())
+            {
+              closest_match = set_meth;
+              closest_match_end_line = end_line;
+            }
+        }
+    }
+
   return closest_match;
 }
 
--- a/libinterp/parse-tree/bp-table.cc	Fri May 10 17:57:29 2024 -0400
+++ b/libinterp/parse-tree/bp-table.cc	Sat May 11 15:03:00 2024 -0400
@@ -800,7 +800,11 @@
     if (line < 0)
       return nullptr;
 
-    return m_cls.get_method (line).user_code_value (true);
+    octave_value method = m_cls.get_method (line);
+    if (method.is_function_handle ())
+      return method.user_function_value ()->user_code_value (true);
+    else
+      return method.user_code_value (true);
   }
 
   bool is_function () const { return m_fcn; }
@@ -847,6 +851,31 @@
               if (fcn != nullptr)
                 m_methods_cache.push_back (fcn);
             }
+
+
+          // Check get and set methods of properties
+          const std::map<std::string, cdef_property>& prop_map
+            = m_cls.get_property_map (cdef_class::property_all);
+          for (auto iter = prop_map.cbegin (); iter != prop_map.cend (); ++iter)
+            {
+              octave_value get_meth = iter->second.get ("GetMethod");
+              if (get_meth.is_function_handle ())
+                {
+                  octave_user_code *fcn
+                    = get_meth.user_function_value ()->user_code_value (true);
+                  if (fcn != nullptr)
+                    m_methods_cache.push_back (fcn);
+                }
+
+              octave_value set_meth = iter->second.get ("SetMethod");
+              if (set_meth.is_function_handle ())
+                {
+                  octave_user_code *fcn
+                    = set_meth.user_function_value ()->user_code_value (true);
+                  if (fcn != nullptr)
+                    m_methods_cache.push_back (fcn);
+                }
+            }
         }
   }
 
--- a/libinterp/parse-tree/pt-eval.cc	Fri May 10 17:57:29 2024 -0400
+++ b/libinterp/parse-tree/pt-eval.cc	Sat May 11 15:03:00 2024 -0400
@@ -3064,11 +3064,42 @@
           cdef_class cls = cdm.find_class (dispatch_type, false);
           if (cls.ok () && cls.get_name () == dispatch_type)
             {
-              cdef_method meth = cls.find_method (method);
-              if (meth.ok () && meth.get_name () == method)
-                fcn = meth.get_function ();
+              if (! method.compare (0, 4, "get."))
+                {
+                  // find get method of classdef property
+                  std::string prop_name = method.substr (4);
+                  cdef_property prop = cls.find_property (prop_name);
+                  if (prop.ok () && prop.get_name () == prop_name)
+                    {
+                      const octave_value& get_meth = prop.get ("GetMethod");
+                      if (get_meth.is_function_handle ())
+                        return get_meth.user_function_value ()->user_code_value ();
+                      else
+                        return nullptr;
+                    }
+                }
+              else if (! method.compare (0, 4, "set."))
+                {
+                  // find set method of classdef property
+                  std::string prop_name = method.substr (4);
+                  cdef_property prop = cls.find_property (prop_name);
+                  if (prop.ok () && prop.get_name () == prop_name)
+                    {
+                      const octave_value& set_meth = prop.get ("SetMethod");
+                      if (set_meth.is_function_handle ())
+                        return set_meth.user_function_value ()->user_code_value ();
+                      else
+                        return nullptr;
+                    }
+                }
               else
-                return nullptr;
+                {
+                  cdef_method meth = cls.find_method (method);
+                  if (meth.ok () && meth.get_name () == method)
+                    fcn = meth.get_function ();
+                  else
+                    return nullptr;
+                }
             }
 
           // If there is no classdef method, then try legacy classes.
--- a/scripts/plot/appearance/legend.m	Fri May 10 17:57:29 2024 -0400
+++ b/scripts/plot/appearance/legend.m	Sat May 11 15:03:00 2024 -0400
@@ -1072,7 +1072,7 @@
   persistent lprops = {"color", "linestyle", "linewidth"};
   persistent mprops = {"color", "marker", "markeredgecolor", ...
                        "markerfacecolor", "markersize"};
-  persistent pprops = {"edgecolor", "facecolor", "cdata", ...
+  persistent pprops = {"edgecolor", "facecolor", ...
                        "linestyle", "linewidth", ...
                        "marker", "markeredgecolor", ...
                        "markerfacecolor", "markersize"};
@@ -1125,11 +1125,16 @@
     case {"patch", "surface"}
 
       vals = get (hplt, pprops);
+      cdata = get (hplt, "cdata");
 
-      hicon = __go_patch__ (hl, [pprops; vals]{:});
+      hicon = __go_patch__ (hl, [pprops; vals]{:}, ...
+                            "cdata", median (median (cdata, 1), 2));
 
       ## Listeners
       safe_property_link (hplt(1), hicon, pprops);
+      addlistener (hplt, "cdata", ...
+                   @(h, ~) set (hicon, "cdata", ...
+                                median (median (get (h, "cdata"), 1), 2)));
 
       setappdata (hicon, "__creator__", typ);
 
@@ -1171,7 +1176,9 @@
       ## Main patch
 
       vals = get (hplt(1), pprops);
-      hicon = __go_patch__ (hl, [pprops; vals]{:}, ...
+      cdata = get (hplt(1), "cdata");
+      hicon = __go_patch__ (hl, "cdata", cdata, ...
+                            [pprops; vals]{:}, ...
                             "pickableparts", "all", ...
                             "buttondownfcn", ...
                             {@execute_itemhit, hl, hplt, "icon"});
@@ -1181,15 +1188,17 @@
 
       ## Additional patch for the inner contour
       vals = get (hplt(end), pprops);
+      cdata = get (hplt(end), "cdata");
       htmp =  __go_patch__ (hl, "handlevisibility", "off", ...
-                            "xdata", 0, "ydata", 0, [pprops; vals]{:}, ...
+                            "xdata", 0, "ydata", 0, "cdata", cdata, ...
+                            [pprops; vals]{:}, ...
                             "pickableparts", "all", ...
                             "buttondownfcn", ...
                             {@execute_itemhit, hl, hplt, "icon"});
 
       ## Listeners
-      safe_property_link (hplt(1), hicon, pprops);
-      safe_property_link (hplt(end), htmp, pprops);
+      safe_property_link (hplt(1), hicon, [{"cdata"}, pprops]);
+      safe_property_link (hplt(end), htmp, [{"cdata"}, pprops]);
       addlistener (hicon, "ydata", ...
                    @(h, ~) set (htmp, "ydata", get (h, "innerydata")));
       addlistener (hicon, "xdata", ...
@@ -1911,6 +1920,20 @@
 %! title ("legend() works for surface objects too");
 
 %!demo
+%! clf;
+%! [x,y,z] = meshgrid (-.2:0.02:.2, -.2:0.02:.2, -.2:0.02:.2);
+%! val = (x.^2 + y.^2 + z.^2);
+%!
+%! h_axes = axes ();
+%! view (3);
+%! fv = isosurface (x, y, z, val, .039, z);
+%! h_patch = patch (fv, "FaceColor", "flat", "EdgeColor", "none");
+%! view (3);
+%! axis tight
+%! axis equal
+%! legend ({"colored patch"});
+
+%!demo
 %! clf reset;  # needed to undo colormap assignment in previous demo
 %! rand_2x3_data2 = [0.44804, 0.84368, 0.23012; 0.72311, 0.58335, 0.90531];
 %! bar (rand_2x3_data2);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/classdef-debug/classdef_breakpoints2.m	Sat May 11 15:03:00 2024 -0400
@@ -0,0 +1,19 @@
+classdef classdef_breakpoints2 < handle
+  properties (Dependent)
+    m_prop;
+  endproperties
+  properties (SetAccess=private)
+    m_prop_value = [];
+  endproperties
+  methods
+    function this = classdef_breakpoints2 (prop)
+      this.m_prop = prop;
+    endfunction
+    function val = get.m_prop (this)
+      val = this.m_prop_value;
+    endfunction
+    function set.m_prop (this, val)
+      this.m_prop_value = val;
+    endfunction
+  endmethods
+endclassdef
--- a/test/classdef-debug/module.mk	Fri May 10 17:57:29 2024 -0400
+++ b/test/classdef-debug/module.mk	Sat May 11 15:03:00 2024 -0400
@@ -1,5 +1,6 @@
 classdef_breakpoints_TEST_FILES = \
   %reldir%/classdef_breakpoints.m \
+  %reldir%/classdef_breakpoints2.m \
   %reldir%/test-classdef-breakpoints.tst
 
 TEST_FILES += $(classdef_breakpoints_TEST_FILES)
--- a/test/classdef-debug/test-classdef-breakpoints.tst	Fri May 10 17:57:29 2024 -0400
+++ b/test/classdef-debug/test-classdef-breakpoints.tst	Sat May 11 15:03:00 2024 -0400
@@ -30,6 +30,7 @@
 %!   dbclear classdef_breakpoints;
 %!   assert_dbstatus ([]);
 %! unwind_protect_cleanup
+%!   dbclear classdef_breakpoints;
 %!   if (isguirunning ())
 %!     __event_manager_gui_preference__ ("editor/show_dbg_file", orig_show_dbg);
 %!   endif
@@ -59,13 +60,14 @@
 %!   dbclear classdef_breakpoints;
 %!   assert_dbstatus ([]);
 %! unwind_protect_cleanup
+%!   dbclear classdef_breakpoints;
 %!   if (isguirunning ())
 %!     __event_manager_gui_preference__ ("editor/show_dbg_file", orig_show_dbg);
 %!   endif
 %! end_unwind_protect
 
 ## Try to add breakpoint in non-existent method
-%!test <65610*>
+%!test <*65610>
 %! if (isguirunning ())
 %!   orig_show_dbg = __event_manager_gui_preference__ ("editor/show_dbg_file",
 %!                                                     "false");
@@ -89,7 +91,64 @@
 %!   dbstop classdef_breakpoints 19;
 %!   assert_dbstatus ([20]);
 %! unwind_protect_cleanup
+%!   dbclear classdef_breakpoints;
+%!   if (isguirunning ())
+%!     __event_manager_gui_preference__ ("editor/show_dbg_file", orig_show_dbg);
+%!   endif
+%! end_unwind_protect
+
+## Set breakpoints in set or get methods by line numbers
+%!test <*65610>
+%! if (isguirunning ())
+%!   orig_show_dbg = __event_manager_gui_preference__ ("editor/show_dbg_file",
+%!                                                     "false");
+%! endif
+%! unwind_protect
+%!   ## Add breakpoints in different member functions using line numbers.
+%!   dbstop classdef_breakpoints2 13 16 10;
+%!   assert_dbstatus ([10, 13, 16]);
+%!
+%!   ## Remove one breakpoint and confirm the others remain.
+%!   dbclear classdef_breakpoints2 16;
+%!   assert_dbstatus ([10, 13]);
+%!
+%!   ## Clear all breakpoints, none should be left.
+%!   dbclear classdef_breakpoints2;
+%!   assert_dbstatus ([]);
+%! unwind_protect_cleanup
+%!   dbclear classdef_breakpoints2;
 %!   if (isguirunning ())
 %!     __event_manager_gui_preference__ ("editor/show_dbg_file", orig_show_dbg);
 %!   endif
 %! end_unwind_protect
+
+## Set breakpoints in set or get methods by method name
+%!test
+%! if (isguirunning ())
+%!   orig_show_dbg = __event_manager_gui_preference__ ("editor/show_dbg_file",
+%!                                                     "false");
+%! endif
+%! unwind_protect
+%!   ## Add breakpoint in constructor
+%!   dbstop @classdef_breakpoints2/classdef_breakpoints2;
+%!   assert_dbstatus ([10]);
+%!
+%!   ## Add breakpoints in methods.
+%!   dbstop @classdef_breakpoints2/get.m_prop;
+%!   dbstop @classdef_breakpoints2/set.m_prop;
+%!   assert_dbstatus ([10, 13, 16]);
+%!
+%!   ## Remove breakpoint from one method.
+%!   dbclear @classdef_breakpoints2/get.m_prop;
+%!   assert_dbstatus ([10, 16]);
+%!
+%!   ## Clear all breakpoints, none should be left.
+%!   dbclear classdef_breakpoints2;
+%!   assert_dbstatus ([]);
+%! unwind_protect_cleanup
+%!   dbclear classdef_breakpoints2;
+%!   if (isguirunning ())
+%!     __event_manager_gui_preference__ ("editor/show_dbg_file", orig_show_dbg);
+%!   endif
+%! end_unwind_protect
+