changeset 10832:1b2fcd122c6a

allow user detect ignored outputs in m-functions
author Jaroslav Hajek <highegg@gmail.com>
date Thu, 29 Jul 2010 12:45:23 +0200
parents 1646bd8e3735
children e5c752231985
files src/ChangeLog src/ov-base.cc src/ov-base.h src/ov-usr-fcn.cc src/ov-usr-fcn.h src/ov.cc src/ov.h src/pt-assign.cc src/pt-exp.cc src/pt-exp.h src/pt-idx.cc src/pt-idx.h src/pt-misc.cc
diffstat 13 files changed, 255 insertions(+), 13 deletions(-) [+]
line wrap: on
line diff
--- a/src/ChangeLog	Thu Jul 29 08:51:23 2010 +0200
+++ b/src/ChangeLog	Thu Jul 29 12:45:23 2010 +0200
@@ -1,3 +1,31 @@
+2010-07-29  Jaroslav Hajek  <highegg@gmail.com>
+
+	* ov.cc (octave_value::subsref (..., const std::list<octave_lvalue> *)
+	octave_value::do_multi_index_op (..., const std::list<octave_lvalue> *)): 
+	New methods.
+	* ov.h: Declare them.
+	* ov-base.cc (octave_base_value::subsref (..., const std::list<octave_lvalue> *)
+	octave_base_value::do_multi_index_op (..., const std::list<octave_lvalue> *)): 
+	New methods.
+	* ov-base.h: Declare them.
+	* ov-usr-fcn.cc (octave_user_function::subsref (..., const std::list<octave_lvalue> *)
+	octave_user_function::do_multi_index_op (..., const std::list<octave_lvalue> *)): 
+	New virtual method overrides. Move code here.
+	(octave_user_function::bind_automatic_vars): Add lvalue_list
+	parameter. Bind automatic variable ".ignored.".
+	(Fis_ignored_output): New defun.
+	* ov-usr-fcn.h: Update decls.
+	* pt-misc.cc (tree_parameter_list::initialize_undefined_elements):
+	Skip warning if outputs are ignored.
+	* pt-exp.cc (tree_expression::rvalue (..., const
+	std::list<octave_lvalue> *)): New method overload.
+	* pt-exp.h: Declare it.
+	* pt-idx.cc (tree_index_expression::rvalue (..., const
+	std::list<octave_lvalue> *)): New method override. Move code here.
+	* pt-idx.h: Declare it.
+	* pt-assign.cc (tree_multi_assignment::rvalue): Pass in the pointer to
+	lvalue_list.
+
 2010-07-28  John W. Eaton  <jwe@octave.org>
 
 	* DLD-FUNCTIONS/find.cc (Ffind): Reorder cases to check for
--- a/src/ov-base.cc	Thu Jul 29 08:51:23 2010 +0200
+++ b/src/ov-base.cc	Thu Jul 29 12:45:23 2010 +0200
@@ -179,6 +179,16 @@
   return subsref (type, idx);
 }
 
+octave_value_list
+octave_base_value::subsref (const std::string& type,
+                            const std::list<octave_value_list>& idx,
+                            int nargout,
+                            const std::list<octave_lvalue> *)
+{
+  // Fall back to call without passing lvalue list.
+  return subsref (type, idx, nargout);
+}
+
 octave_value
 octave_base_value::do_index_op (const octave_value_list&, bool)
 {
@@ -195,6 +205,14 @@
   return octave_value ();
 }
 
+octave_value_list
+octave_base_value::do_multi_index_op (int nargout, const octave_value_list& idx,
+                                      const std::list<octave_lvalue> *)
+{
+  // Fall back.
+  return do_multi_index_op (nargout, idx);
+}
+
 idx_vector
 octave_base_value::index_vector (void) const
 {
--- a/src/ov-base.h	Thu Jul 29 08:51:23 2010 +0200
+++ b/src/ov-base.h	Thu Jul 29 12:45:23 2010 +0200
@@ -260,12 +260,22 @@
            const std::list<octave_value_list>& idx,
            bool auto_add);
 
+  virtual octave_value_list
+  subsref (const std::string& type,
+           const std::list<octave_value_list>& idx,
+           int nargout,
+           const std::list<octave_lvalue> *lvalue_list);
+
   virtual octave_value
   do_index_op (const octave_value_list& idx, bool resize_ok = false);
 
   virtual octave_value_list
   do_multi_index_op (int nargout, const octave_value_list& idx);
 
+  virtual octave_value_list
+  do_multi_index_op (int nargout, const octave_value_list& idx,
+                     const std::list<octave_lvalue> *lvalue_list);
+
   virtual void assign (const std::string&, const octave_value&) { }
 
   virtual octave_value
--- a/src/ov-usr-fcn.cc	Thu Jul 29 08:51:23 2010 +0200
+++ b/src/ov-usr-fcn.cc	Thu Jul 29 12:45:23 2010 +0200
@@ -31,6 +31,7 @@
 #include "Cell.h"
 #include "defun.h"
 #include "error.h"
+#include "gripes.h"
 #include "input.h"
 #include "oct-obj.h"
 #include "ov-usr-fcn.h"
@@ -282,6 +283,14 @@
                                const std::list<octave_value_list>& idx,
                                int nargout)
 {
+  return octave_user_function::subsref (type, idx, nargout, 0);
+}
+
+octave_value_list
+octave_user_function::subsref (const std::string& type,
+                               const std::list<octave_value_list>& idx,
+                               int nargout, const std::list<octave_lvalue>* lvalue_list)
+{
   octave_value_list retval;
 
   switch (type[0])
@@ -290,7 +299,8 @@
       {
         int tmp_nargout = (type.length () > 1 && nargout == 0) ? 1 : nargout;
 
-        retval = do_multi_index_op (tmp_nargout, idx.front ());
+        retval = do_multi_index_op (tmp_nargout, idx.front (),
+                                    idx.size () == 1 ? lvalue_list : 0);
       }
       break;
 
@@ -320,6 +330,14 @@
 octave_user_function::do_multi_index_op (int nargout,
                                          const octave_value_list& args)
 {
+  return do_multi_index_op (nargout, args, 0);
+}
+
+octave_value_list
+octave_user_function::do_multi_index_op (int nargout,
+                                         const octave_value_list& args,
+                                         const std::list<octave_lvalue>* lvalue_list)
+{
   octave_value_list retval;
 
   if (error_state)
@@ -392,7 +410,8 @@
       frame.add_fcn (symbol_table::clear_variables);
     }
 
-  bind_automatic_vars (arg_names, nargin, nargout, all_va_args (args));
+  bind_automatic_vars (arg_names, nargin, nargout, all_va_args (args),
+                       lvalue_list);
 
   bool echo_commands = (Vecho_executing_commands & ECHO_FUNCTIONS);
 
@@ -522,7 +541,7 @@
 void
 octave_user_function::bind_automatic_vars
   (const string_vector& arg_names, int nargin, int nargout,
-   const octave_value_list& va_args)
+   const octave_value_list& va_args, const std::list<octave_lvalue> *lvalue_list)
 {
   if (! arg_names.empty ())
     symbol_table::varref ("argn") = arg_names;
@@ -535,6 +554,31 @@
 
   if (takes_varargs ())
     symbol_table::varref ("varargin") = va_args.cell_value ();
+  
+  if (lvalue_list)
+    {
+      octave_idx_type nbh = 0;
+      for (std::list<octave_lvalue>::const_iterator p = lvalue_list->begin ();
+           p != lvalue_list->end (); p++)
+        nbh += p->is_black_hole ();
+
+      if (nbh > 0)
+        {
+          // Only assign the hidden variable if black holes actually present.
+          Matrix bh (1, nbh);
+          octave_idx_type k = 0, l = 0;
+          for (std::list<octave_lvalue>::const_iterator p = lvalue_list->begin ();
+               p != lvalue_list->end (); p++)
+            {
+              if (p->is_black_hole ())
+                bh(l++) = k+1;
+              k += p->numel ();
+            }
+
+          symbol_table::varref (".ignored.") = bh;
+          symbol_table::mark_hidden (".ignored.");
+        }
+    }
 }
 
 DEFUN (nargin, args, ,
@@ -683,3 +727,69 @@
 {
   return SET_INTERNAL_VARIABLE (optimize_subsasgn_calls);
 }
+
+static bool val_in_table (const Matrix& table, double val)
+{
+  if (table.is_empty ())
+    return false;
+
+  octave_idx_type i = table.lookup (val, ASCENDING);
+  return (i > 0 && table(i-1) == val);
+}
+
+DEFUN (is_ignored_output, args, ,
+  "-*- texinfo -*-\n\
+@deftypefn {Built-in Function} {} is_ignored_output (@var{k})\n\
+Within a function, given an index @var{k} within the range @code{1:nargout},\n\
+return a logical value indicating whether the argument will be ignored on output\n\
+using the tilde (~) special output argument. If @var{k} is outside the range,\n\
+the function yields false. @var{k} can also be an array, in which case the function\n\
+works element-wise and a logical array is returned.\n\
+\n\
+At the top level, @code{is_ignored_output} returns an error.\n\
+@seealso{nargout, nargin, varargin, varargout}\n\
+@end deftypefn")
+{
+  octave_value retval;
+
+  int nargin = args.length ();
+
+  if (nargin == 1)
+    {
+      if (! symbol_table::at_top_level ())
+        {
+          Matrix ignored;
+          octave_value tmp = symbol_table::varval (".ignored.");
+          if (tmp.is_defined ())
+            ignored = tmp.matrix_value ();
+
+          if (args(0).is_scalar_type ())
+            {
+              double k = args(0).double_value ();
+              if (! error_state)
+                retval = val_in_table (ignored, k);
+            }
+          else if (args(0).is_numeric_type ())
+            {
+              const NDArray ka = args(0).array_value ();
+              if (! error_state)
+                {
+                  boolNDArray r (ka.dims ());
+                  for (octave_idx_type i = 0; i < ka.numel (); i++)
+                    r(i) = val_in_table (ignored, ka(i));
+
+                  retval = r;
+                }
+            }
+          else
+            gripe_wrong_type_arg ("is_ignored_output", args(0));
+        }
+      else
+        error ("is_ignored_output: invalid call at top level");
+    }
+  else
+    print_usage ();
+
+  return retval;
+}
+
--- a/src/ov-usr-fcn.h	Thu Jul 29 08:51:23 2010 +0200
+++ b/src/ov-usr-fcn.h	Thu Jul 29 12:45:23 2010 +0200
@@ -268,9 +268,17 @@
                              const std::list<octave_value_list>& idx,
                              int nargout);
 
+  octave_value_list subsref (const std::string& type,
+                             const std::list<octave_value_list>& idx,
+                             int nargout, const std::list<octave_lvalue>* lvalue_list);
+
   octave_value_list
   do_multi_index_op (int nargout, const octave_value_list& args);
 
+  octave_value_list
+  do_multi_index_op (int nargout, const octave_value_list& args, 
+                     const std::list<octave_lvalue>* lvalue_list);
+
   tree_parameter_list *parameter_list (void) { return param_list; }
 
   tree_parameter_list *return_list (void) { return ret_list; }
@@ -382,7 +390,8 @@
   void print_code_function_trailer (void);
 
   void bind_automatic_vars (const string_vector& arg_names, int nargin,
-                            int nargout, const octave_value_list& va_args);
+                            int nargout, const octave_value_list& va_args,
+                            const std::list<octave_lvalue> *lvalue_list);
 
   // No copying!
 
--- a/src/ov.cc	Thu Jul 29 08:51:23 2010 +0200
+++ b/src/ov.cc	Thu Jul 29 12:45:23 2010 +0200
@@ -1202,6 +1202,17 @@
     return rep->subsref (type, idx, nargout);
 }
 
+octave_value_list
+octave_value::subsref (const std::string& type,
+                       const std::list<octave_value_list>& idx, int nargout,
+                       const std::list<octave_lvalue> *lvalue_list)
+{
+  if (lvalue_list)
+    return rep->subsref (type, idx, nargout, lvalue_list);
+  else
+    return subsref (type, idx, nargout);
+}
+
 octave_value
 octave_value::next_subsref (const std::string& type,
                             const std::list<octave_value_list>& idx,
@@ -1256,6 +1267,13 @@
   return rep->do_multi_index_op (nargout, idx);
 }
 
+octave_value_list
+octave_value::do_multi_index_op (int nargout, const octave_value_list& idx,
+                                 const std::list<octave_lvalue> *lvalue_list)
+{
+  return rep->do_multi_index_op (nargout, idx, lvalue_list);
+}
+
 #if 0
 static void
 gripe_assign_failed (const std::string& on, const std::string& tn1,
--- a/src/ov.h	Thu Jul 29 08:51:23 2010 +0200
+++ b/src/ov.h	Thu Jul 29 12:45:23 2010 +0200
@@ -391,6 +391,11 @@
                              const std::list<octave_value_list>& idx,
                              int nargout);
 
+  octave_value_list subsref (const std::string& type,
+                             const std::list<octave_value_list>& idx,
+                             int nargout,
+                             const std::list<octave_lvalue> *lvalue_list);
+
   octave_value next_subsref (const std::string& type, const
                              std::list<octave_value_list>& idx,
                              size_t skip = 1);
@@ -411,6 +416,10 @@
   octave_value_list
   do_multi_index_op (int nargout, const octave_value_list& idx);
 
+  octave_value_list
+  do_multi_index_op (int nargout, const octave_value_list& idx,
+                     const std::list<octave_lvalue> *lvalue_list);
+
   octave_value subsasgn (const std::string& type,
                                  const std::list<octave_value_list>& idx,
                                  const octave_value& rhs);
--- a/src/pt-assign.cc	Thu Jul 29 08:51:23 2010 +0200
+++ b/src/pt-assign.cc	Thu Jul 29 12:45:23 2010 +0200
@@ -354,7 +354,7 @@
       if (error_state)
         return retval;
 
-      int n_out = 0;
+      octave_idx_type n_out = 0;
 
       for (std::list<octave_lvalue>::const_iterator p = lvalue_list.begin ();
            p != lvalue_list.end ();
@@ -362,7 +362,7 @@
         n_out += p->numel ();
 
       // The following trick is used to keep rhs_val constant.
-      const octave_value_list rhs_val1 = rhs->rvalue (n_out);
+      const octave_value_list rhs_val1 = rhs->rvalue (n_out, &lvalue_list);
       const octave_value_list rhs_val = (rhs_val1.length () == 1 && rhs_val1(0).is_cs_list ()
                                          ? rhs_val1(0).list_value () : rhs_val1);
 
--- a/src/pt-exp.cc	Thu Jul 29 08:51:23 2010 +0200
+++ b/src/pt-exp.cc	Thu Jul 29 12:45:23 2010 +0200
@@ -69,6 +69,12 @@
   return octave_value_list ();
 }
 
+octave_value_list
+tree_expression::rvalue (int nargout, const std::list<octave_lvalue> *)
+{
+  return rvalue (nargout);
+}
+
 octave_lvalue
 tree_expression::lvalue (void)
 {
--- a/src/pt-exp.h	Thu Jul 29 08:51:23 2010 +0200
+++ b/src/pt-exp.h	Thu Jul 29 12:45:23 2010 +0200
@@ -25,6 +25,7 @@
 #define octave_tree_expr_h 1
 
 #include <string>
+#include <list>
 
 class octave_value;
 class octave_lvalue;
@@ -78,6 +79,9 @@
 
   virtual octave_value_list rvalue (int nargout);
 
+  virtual octave_value_list rvalue (int nargout,
+                                    const std::list<octave_lvalue> *lvalue_list);
+
   virtual octave_lvalue lvalue (void);
 
   int paren_count (void) const { return num_parens; }
--- a/src/pt-idx.cc	Thu Jul 29 08:51:23 2010 +0200
+++ b/src/pt-idx.cc	Thu Jul 29 12:45:23 2010 +0200
@@ -275,6 +275,12 @@
 octave_value_list
 tree_index_expression::rvalue (int nargout)
 {
+  return tree_index_expression::rvalue (nargout, 0);
+}
+
+octave_value_list
+tree_index_expression::rvalue (int nargout, const std::list<octave_lvalue> *lvalue_list)
+{
   octave_value_list retval;
 
   if (error_state)
@@ -398,7 +404,8 @@
         }
 
       if (! error_state)
-        retval = tmp.subsref (type.substr (tmpi, n - tmpi), idx, nargout);
+        retval = tmp.subsref (type.substr (tmpi, n - tmpi), idx, nargout,
+                              lvalue_list);
     }
 
   return retval;
--- a/src/pt-idx.h	Thu Jul 29 08:51:23 2010 +0200
+++ b/src/pt-idx.h	Thu Jul 29 12:45:23 2010 +0200
@@ -86,6 +86,8 @@
 
   octave_value_list rvalue (int nargout);
 
+  octave_value_list rvalue (int nargout, const std::list<octave_lvalue> *lvalue_list);
+
   octave_lvalue lvalue (void);
 
   tree_index_expression *dup (symbol_table::scope_id scope,
--- a/src/pt-misc.cc	Thu Jul 29 08:51:23 2010 +0200
+++ b/src/pt-misc.cc	Thu Jul 29 12:45:23 2010 +0200
@@ -125,13 +125,17 @@
 
 void
 tree_parameter_list::initialize_undefined_elements (const std::string& warnfor,
-                                                    int nargout,
-                                                    const octave_value& val)
+                                                    int nargout, const octave_value& val)
 {
   bool warned = false;
 
   int count = 0;
 
+  octave_value tmp = symbol_table::varval (".ignored.");
+  const Matrix ignored = tmp.is_defined () ? tmp.matrix_value () : Matrix ();
+
+  octave_idx_type k = 0;
+
   for (iterator p = begin (); p != end (); p++)
     {
       if (++count > nargout)
@@ -145,10 +149,27 @@
             {
               warned = true;
 
-              warning_with_id
-                ("Octave:undefined-return-values",
-                 "%s: some elements in list of return values are undefined",
-                 warnfor.c_str ());
+              while (k < ignored.numel ())
+                {
+                  octave_idx_type l = ignored (k);
+                  if (l == count)
+                    {
+                      warned = false;
+                      break;
+                    }
+                  else if (l > count)
+                    break;
+                  else
+                    k++;
+                }
+
+              if (warned)
+                {
+                  warning_with_id
+                    ("Octave:undefined-return-values",
+                     "%s: some elements in list of return values are undefined",
+                     warnfor.c_str ());
+                }
             }
 
           octave_lvalue tmp = elt->lvalue ();