changeset 18314:06eb893b9db6

Implement subsref overloading in classdef. * ov-class.cc (sanitize, make_idx_args): Moved function to ov-base.cc. * ov-base.cc (sanitize, make_idx_args): Moved from ov-class.cc. * ov-base.h (make_udx_args): New API function declaration. * ov-classdef.cc (in_class_method): New utility static function. (octave_classdef::subsref): Use overloaded subsref method if present, only when not already in a class method.
author Michael Goffioul <michael.goffioul@gmail.com>
date Mon, 20 Jan 2014 14:10:42 -0500
parents 9d62b5f041ee
children ff311e5ff6d8
files libinterp/octave-value/ov-base.cc libinterp/octave-value/ov-base.h libinterp/octave-value/ov-class.cc libinterp/octave-value/ov-classdef.cc
diffstat 4 files changed, 137 insertions(+), 95 deletions(-) [+]
line wrap: on
line diff
--- a/libinterp/octave-value/ov-base.cc	Mon Jan 20 01:41:26 2014 -0500
+++ b/libinterp/octave-value/ov-base.cc	Mon Jan 20 14:10:42 2014 -0500
@@ -1536,6 +1536,97 @@
   return new octave_cell ();
 }
 
+static inline octave_value_list
+sanitize (const octave_value_list& ovl)
+{
+  octave_value_list retval = ovl;
+
+  for (octave_idx_type i = 0; i < ovl.length (); i++)
+    {
+      if (retval(i).is_magic_colon ())
+        retval(i) = ":";
+    }
+
+  return retval;
+}
+
+octave_value
+make_idx_args (const std::string& type,
+               const std::list<octave_value_list>& idx,
+               const std::string& who)
+{
+  octave_value retval;
+
+  size_t len = type.length ();
+
+  if (len == idx.size ())
+    {
+      Cell type_field (1, len);
+      Cell subs_field (1, len);
+
+      std::list<octave_value_list>::const_iterator p = idx.begin ();
+
+      for (size_t i = 0; i < len; i++)
+        {
+          char t = type[i];
+
+          switch (t)
+            {
+            case '(':
+              type_field(i) = "()";
+              subs_field(i) = Cell (sanitize (*p++));
+              break;
+
+            case '{':
+              type_field(i) = "{}";
+              subs_field(i) = Cell (sanitize (*p++));
+              break;
+
+            case '.':
+              {
+                type_field(i) = ".";
+
+                octave_value_list vlist = *p++;
+
+                if (vlist.length () == 1)
+                  {
+                    octave_value val = vlist(0);
+
+                    if (val.is_string ())
+                      subs_field(i) = val;
+                    else
+                      {
+                        error ("expecting character string argument for '.' index");
+                        return retval;
+                      }
+                  }
+                else
+                  {
+                    error ("expecting single argument for '.' index");
+                    return retval;
+                  }
+              }
+              break;
+
+            default:
+              panic_impossible ();
+              break;
+            }
+        }
+
+      octave_map m;
+
+      m.assign ("type", type_field);
+      m.assign ("subs", subs_field);
+
+      retval = m;
+    }
+  else
+    error ("invalid index for %s", who.c_str ());
+
+  return retval;
+}
+
 void
 install_base_type_conversions (void)
 {
--- a/libinterp/octave-value/ov-base.h	Mon Jan 20 01:41:26 2014 -0500
+++ b/libinterp/octave-value/ov-base.h	Mon Jan 20 14:10:42 2014 -0500
@@ -828,4 +828,12 @@
 // is memory to be saved
 extern OCTINTERP_API bool Vsparse_auto_mutate;
 
+// Utility function to convert C++ arguments used in subsref/subsasgn into an
+// octave_value_list object that can be used to call a function/method in the
+// interpreter.
+extern OCTINTERP_API octave_value
+make_idx_args (const std::string& type,
+               const std::list<octave_value_list>& idx,
+               const std::string& who);
+
 #endif
--- a/libinterp/octave-value/ov-class.cc	Mon Jan 20 01:41:26 2014 -0500
+++ b/libinterp/octave-value/ov-class.cc	Mon Jan 20 14:10:42 2014 -0500
@@ -268,97 +268,6 @@
   error ("assignment to class element failed");
 }
 
-static inline octave_value_list
-sanitize (const octave_value_list& ovl)
-{
-  octave_value_list retval = ovl;
-
-  for (octave_idx_type i = 0; i < ovl.length (); i++)
-    {
-      if (retval(i).is_magic_colon ())
-        retval(i) = ":";
-    }
-
-  return retval;
-}
-
-static inline octave_value
-make_idx_args (const std::string& type,
-               const std::list<octave_value_list>& idx,
-               const std::string& who)
-{
-  octave_value retval;
-
-  size_t len = type.length ();
-
-  if (len == idx.size ())
-    {
-      Cell type_field (1, len);
-      Cell subs_field (1, len);
-
-      std::list<octave_value_list>::const_iterator p = idx.begin ();
-
-      for (size_t i = 0; i < len; i++)
-        {
-          char t = type[i];
-
-          switch (t)
-            {
-            case '(':
-              type_field(i) = "()";
-              subs_field(i) = Cell (sanitize (*p++));
-              break;
-
-            case '{':
-              type_field(i) = "{}";
-              subs_field(i) = Cell (sanitize (*p++));
-              break;
-
-            case '.':
-              {
-                type_field(i) = ".";
-
-                octave_value_list vlist = *p++;
-
-                if (vlist.length () == 1)
-                  {
-                    octave_value val = vlist(0);
-
-                    if (val.is_string ())
-                      subs_field(i) = val;
-                    else
-                      {
-                        error ("expecting character string argument for '.' index");
-                        return retval;
-                      }
-                  }
-                else
-                  {
-                    error ("expecting single argument for '.' index");
-                    return retval;
-                  }
-              }
-              break;
-
-            default:
-              panic_impossible ();
-              break;
-            }
-        }
-
-      octave_map m;
-
-      m.assign ("type", type_field);
-      m.assign ("subs", subs_field);
-
-      retval = m;
-    }
-  else
-    error ("invalid index for %s", who.c_str ());
-
-  return retval;
-}
-
 Cell
 octave_class::dotref (const octave_value_list& idx)
 {
--- a/libinterp/octave-value/ov-classdef.cc	Mon Jan 20 01:41:26 2014 -0500
+++ b/libinterp/octave-value/ov-classdef.cc	Mon Jan 20 14:10:42 2014 -0500
@@ -305,6 +305,14 @@
 }
 
 static bool
+in_class_method (const cdef_class& cls)
+{
+  cdef_class ctx = get_class_context ();
+
+  return (ctx.ok () && is_superclass (ctx, cls));
+}
+
+static bool
 check_access (const cdef_class& cls, const octave_value& acc,
               const std::string& meth_name = std::string (),
               const std::string& prop_name = std::string (),
@@ -885,14 +893,38 @@
   size_t skip = 0;
   octave_value_list retval;
 
-  // FIXME: should check "subsref" method first
+  cdef_class cls = object.get_class ();
+
+  if (! in_class_method (cls))
+    {
+      cdef_method meth = cls.find_method ("subsref");
+
+      if (meth.ok ())
+        {
+          octave_value_list args;
+
+          args(1) = make_idx_args (type, idx, "subsref");
+
+          if (! error_state)
+            {
+              count++;
+              args(0) = octave_value (this);
+
+              retval = meth.execute (args, nargout, true, "subsref");
+            }
+
+          return retval;
+        }
+    }
+
+  // At this point, the default subsref mechanism must be used.
 
   retval = object.subsref (type, idx, nargout, skip, cdef_class ());
 
   if (! error_state)
     {
       if (type.length () > skip && idx.size () > skip)
-	retval = retval(0).next_subsref (nargout, type, idx, skip);
+        retval = retval(0).next_subsref (nargout, type, idx, skip);
     }
 
   return retval;
@@ -906,8 +938,10 @@
   size_t skip = 0;
   octave_value_list retval;
 
-  // FIXME: should check "subsref" method first
-  // ? not sure this still applied with auto_add version of subsref
+  // This variant of subsref is used to create temporary values when doing
+  // assignment with multi-level indexing. AFAIK this is only used for internal
+  // purpose (not sure we should even implement this) and any overload subsref
+  // should not be called.
 
   retval = object.subsref (type, idx, 1, skip, cdef_class (), auto_add);