changeset 7972:5bf4e2c13ed8

make superiorto and inferiorto work
author John W. Eaton <jwe@octave.org>
date Fri, 25 Jul 2008 14:25:35 -0400
parents dd5cc5016487
children e69bca367ed7
files src/ChangeLog src/ov-class.cc src/symtab.cc src/symtab.h
diffstat 4 files changed, 155 insertions(+), 28 deletions(-) [+]
line wrap: on
line diff
--- a/src/ChangeLog	Thu Jul 24 15:42:40 2008 -0400
+++ b/src/ChangeLog	Fri Jul 25 14:25:35 2008 -0400
@@ -1,3 +1,16 @@
+2008-07-25  John W. Eaton  <jwe@octave.org>
+
+	* symtab.cc (get_dispatch_type): New function.
+	(symbol_table::fcn_info::fcn_info_rep::find): Use it.
+
+	* ov-class.cc (set_class_relationship): Delete static function.
+	(Fsuperiorto, Finferiorto): Warn about precedence conflicts.
+	Call symbol_table::set_class_relationship instead of local static
+	function.
+	* symtab.h (symbol_table::class_precedence_table): New data member.
+	(symbol_table::set_class_relationship, symbol_table::is_superiorto):
+	New static functions.
+
 2008-07-24  John W. Eaton  <jwe@octave.org>
 
 	* load-path.h (load_path::dir_info::class_info): New struct.
--- a/src/ov-class.cc	Thu Jul 24 15:42:40 2008 -0400
+++ b/src/ov-class.cc	Fri Jul 25 14:25:35 2008 -0400
@@ -1097,15 +1097,6 @@
   return built_in_class_names.find (cn) != built_in_class_names.end ();
 }
 
-static void
-set_class_relationship (const std::string& sup_class,
-			const std::string& inf_class)
-{
-  // FIXME
-
-  warning ("class precedence not implemented");
-}
-
 DEFUN (superiorto, args, ,
   "-*- texinfo -*-\n\
 @deftypefn {Built-in Function} {} superiorto (@var{class_name})\n\
@@ -1130,7 +1121,10 @@
 		{
 		  std::string this_class_name = fcn->name ();
 
-		  set_class_relationship (this_class_name, class_name);
+		  if (! symbol_table::set_class_relationship (this_class_name,
+							      class_name))
+		    error ("superiorto: precedence already set for %s and %s",
+			   this_class_name.c_str (), class_name.c_str ());
 		}
 	      else
 		{
@@ -1174,7 +1168,13 @@
 		{
 		  std::string this_class_name = fcn->name ();
 
-		  set_class_relationship (class_name, this_class_name);
+		  symbol_table::set_class_relationship (class_name,
+							this_class_name);
+
+		  if (! symbol_table::set_class_relationship (this_class_name,
+							      class_name))
+		    error ("inferiorto: precedence already set for %s and %s",
+			   this_class_name.c_str (), class_name.c_str ());
 		}
 	      else
 		error ("inferiorto: cannot give user-defined class lower precedence than built-in class");
--- a/src/symtab.cc	Thu Jul 24 15:42:40 2008 -0400
+++ b/src/symtab.cc	Fri Jul 25 14:25:35 2008 -0400
@@ -53,6 +53,8 @@
 
 std::map<std::string, symbol_table::fcn_info> symbol_table::fcn_table;
 
+std::map<std::string, std::set<std::string> > symbol_table::class_precedence_table;
+
 const symbol_table::scope_id symbol_table::xglobal_scope = 0;
 const symbol_table::scope_id symbol_table::xtop_scope = 1;
 
@@ -359,6 +361,57 @@
   return retval;
 }
 
+static std::string
+get_dispatch_type (const octave_value_list& evaluated_args)
+{
+  std::string dispatch_type;
+
+  int n = evaluated_args.length ();
+
+  if (n > 0)
+    {
+      // Find first object, if any.
+
+      int i;
+
+      for (i = 0; i < n; i++)
+	{
+	  octave_value arg = evaluated_args(i);
+
+	  if (arg.is_object ())
+	    {
+	      dispatch_type = arg.class_name ();
+	      break;
+	    }
+	}
+
+      for (int j = i+1; j < n; j++)
+	{
+	  octave_value arg = evaluated_args(j);
+
+	  if (arg.is_object ())
+	    {
+	      std::string cname = arg.class_name ();
+
+	      // Only switch to type of ARG if it is marked superior
+	      // to the current DISPATCH_TYPE.
+	      if (! symbol_table::is_superiorto (dispatch_type, cname)
+		  && symbol_table::is_superiorto (cname, dispatch_type))
+		dispatch_type = cname;
+	    }
+	}
+
+      if (dispatch_type.empty ())
+	{
+	  // No object found, so use class of first argument.
+
+	  dispatch_type = evaluated_args(0).class_name ();
+	}
+    }
+
+  return dispatch_type;
+}
+
 // Find the definition of NAME according to the following precedence
 // list:
 //
@@ -519,25 +572,15 @@
 
 	  args_evaluated = true;
 
-	  // FIXME -- need to handle precedence.
-
-	  std::string dispatch_type = evaluated_args(0).class_name ();
-
-	  for (int i = 1; i < n; i++)
+	  if (n > 0)
 	    {
-	      octave_value arg = evaluated_args(i);
+	      std::string dispatch_type = get_dispatch_type (evaluated_args);
 
-	      if (arg.is_object ())
-		{
-		  dispatch_type = arg.class_name ();
-		  break;
-		}
+	      octave_value fcn = find_method (dispatch_type);
+
+	      if (fcn.is_defined ())
+		return fcn;
 	    }
-
-	  octave_value fcn = find_method (dispatch_type);
-
-	  if (fcn.is_defined ())
-	    return fcn;
 	}
       else
 	return octave_value ();
@@ -706,6 +749,65 @@
   return function_on_path;
 }
 
+// Insert INF_CLASS in the set of class names that are considered
+// inferior to SUP_CLASS.  Return FALSE if INF_CLASS is currently
+// marked as superior to  SUP_CLASS.
+
+bool
+symbol_table::set_class_relationship (const std::string& sup_class,
+				      const std::string& inf_class)
+{
+  class_precedence_table_const_iterator p
+    = class_precedence_table.find (inf_class);
+
+  if (p != class_precedence_table.end ())
+    {
+      const std::set<std::string>& inferior_classes = p->second;
+
+      std::set<std::string>::const_iterator q
+	= inferior_classes.find (sup_class);
+
+      if (q != inferior_classes.end ())
+	return false;
+    }
+
+  class_precedence_table[sup_class].insert (inf_class);
+
+  return true;
+}
+
+// Has class A been marked as superior to class B?  Also returns
+// TRUE if B has been marked as inferior to A, since we only keep
+// one table, and convert inferiort information to a superiorto
+// relationship.  Two calls are required to determine whether there
+// is no relationship between two classes:
+//
+//  if (symbol_table::is_superiorto (a, b))
+//    // A is superior to B, or B has been marked inferior to A.
+//  else if (symbol_table::is_superiorto (b, a))
+//    // B is superior to A, or A has been marked inferior to B.
+//  else
+//    // No relation.
+
+bool
+symbol_table::is_superiorto (const std::string& a, const std::string& b)
+{
+  bool retval = false;
+
+  class_precedence_table_const_iterator p = class_precedence_table.find (a);
+
+  if (p != class_precedence_table.end ())
+    {
+      const std::set<std::string>& inferior_classes = p->second;
+      std::set<std::string>::const_iterator q = inferior_classes.find (b);
+
+      if (q != inferior_classes.end ())
+	retval = true;
+    }
+
+  return retval;
+}
+
 static std::string
 fcn_file_name (const octave_value& fcn)
 {
--- a/src/symtab.h	Thu Jul 24 15:42:40 2008 -0400
+++ b/src/symtab.h	Fri Jul 25 14:25:35 2008 -0400
@@ -821,7 +821,7 @@
     void clear_user_function (void) { rep->clear_user_function (); }
     
     void clear_mex_function (void) { rep->clear_mex_function (); }
-    
+
     void add_dispatch (const std::string& type, const std::string& fname)
     {
       rep->add_dispatch (type, fname);
@@ -1396,6 +1396,11 @@
       }
   }
 
+  static bool set_class_relationship (const std::string& sup_class,
+				      const std::string& inf_class);
+
+  static bool is_superiorto (const std::string& a, const std::string& b);
+    
   static void alias_built_in_function (const std::string& alias,
 				       const std::string& name)
   {
@@ -1814,6 +1819,13 @@
   // functions, class constructors, class methods, etc.)
   static std::map<std::string, fcn_info> fcn_table;
 
+  // Mape from class names to set of classes that have lower
+  // precedence.
+  static std::map<std::string, std::set<std::string> > class_precedence_table;
+
+  typedef std::map<std::string, std::set<std::string> >::const_iterator class_precedence_table_const_iterator;
+  typedef std::map<std::string, std::set<std::string> >::iterator class_precedence_table_iterator;
+
   static const scope_id xglobal_scope;
   static const scope_id xtop_scope;