changeset 4930:bdb307dc8613

[project @ 2004-08-05 04:55:26 by jwe]
author jwe
date Thu, 05 Aug 2004 04:55:26 +0000
parents 585e9a8c2ef8
children 1ed883f251e8
files src/ChangeLog src/lex.h src/lex.l src/ov-fcn-handle.cc src/ov-fcn-handle.h src/ov-usr-fcn.cc src/ov.cc src/ov.h src/parse.y src/variables.cc src/variables.h
diffstat 11 files changed, 394 insertions(+), 100 deletions(-) [+]
line wrap: on
line diff
--- a/src/ChangeLog	Tue Aug 03 20:45:34 2004 +0000
+++ b/src/ChangeLog	Thu Aug 05 04:55:26 2004 +0000
@@ -1,3 +1,53 @@
+2004-08-05  John W. Eaton  <jwe@octave.org>
+
+	* variables.h (symbol_exist): Default for type is now "any".
+
+2004-08-05  David Bateman  <dbateman@free.fr>
+
+	* ov-fcn-handle.cc (octave_fcn_handle (const std::string&, 
+	const string_vector&, const std::string&)): New constructor for inline
+	function handles.
+	(octave_fcn_handle::print_raw): Allow inline functions to be printed.
+	(octave_fcn_handle::convert_to_str_internal): New function to allow
+	Fchar to work on inlined function handles.
+	(Finline, Fformula, Fargnames, Fvectorize): New functions.
+	* ov-fcn-handle.h (octave_fcn_handle (const std::string&, 
+	const string_vector&, const std::string&)): Provide decl.
+	(octave_fcn_handle::convert_to_str_internal): Provide decl.
+	(fcn_type): New enum for the type of function handle.
+	(octave_fcn_handle::inline_fcn_text, octave_fcn_handle::is_inline,
+	octave_fcn_handle::inline_fcn_arg_names): New functions.
+	(octave_fcn_handle::typ, octave_fcn_handle::iftext,
+	octave_fcn_handle::ifargs): New private variables for inline functions.
+
+2004-08-04  John W. Eaton  <jwe@octave.org>
+
+	* parse.y (fcn_handle):
+	Recognize '@' FCN_HANDLE rather than just FCN_HANDLE.
+	Decrement lexer_flags.looking_at_function_handle here.
+	* lex.h (lexical_feedback::looking_at_function_handle):
+	New data member.
+	(lexical_feedback::init): Initialize it.
+	* lex.l (handle_identifier): Only reject keywords if we are
+	looking at a function handle.
+	("@"): Recognize this separately from what follows.
+	Increment lexer_flags.looking_at_function_handle here.
+
+	* ov-fcn-handle.h (octave_fcn_handle::octave_fcn_handle
+	(octave_function*, const std::string)): Delete.
+	* ov.h, ov.cc (octave_value::octave_value (octave_function *)): Delete.
+	(octave_value::octave_value (octave_function *, const std::string)):
+	Delete.
+
+	* ov-fcn-handle.h (octave_fcn_handle::fcn): Now octave_value, not
+	pointer to octave_function.
+	(octave_fcn_handle::octave_fcn_handle (const octave_value&, const
+	std::string)): New constructor.
+	* variables.cc (lookup_function): Return octave_value, not pointer
+	to octave_function.  Change all uses.
+	(lookup_user_function): Return octave_value, not pointer
+	to octave_user_function.  Change all uses.
+
 2004-08-03  John W. Eaton  <jwe@octave.org>
 
 	* ov-usr-fcn.cc (octave_user_fcn::do_multi_index_op): Call
--- a/src/lex.h	Tue Aug 03 20:45:34 2004 +0000
+++ b/src/lex.h	Thu Aug 05 04:55:26 2004 +0000
@@ -86,6 +86,9 @@
   // TRUE means we're in the middle of defining a function.
   bool defining_func;
 
+  // Nonzero means we are parsing a function handle.
+  int looking_at_function_handle;
+
   // TRUE means we're parsing the return list for a function.
   bool looking_at_return_list;
 
--- a/src/lex.l	Tue Aug 03 20:45:34 2004 +0000
+++ b/src/lex.l	Thu Aug 05 04:55:26 2004 +0000
@@ -603,8 +603,13 @@
 // Function handles.
 %}
 
-@{IDENT} {
-    TOK_PUSH_AND_RETURN (&yytext[1], FCN_HANDLE);
+"@" {
+    current_input_column++;
+    lexer_flags.quote_is_transpose = false;
+    lexer_flags.cant_be_identifier = false;
+    lexer_flags.convert_spaces_to_comma = false;
+    lexer_flags.looking_at_function_handle++;
+    COUNT_TOK_AND_RETURN ('@');
   }
 
 %{
@@ -2480,12 +2485,24 @@
       return STRUCT_ELT;
     }
 
+  int kw_token = is_keyword_token (tok);
+
+  if (lexer_flags.looking_at_function_handle)
+    {
+      if (kw_token)
+	{
+	  error ("function handles may not refer to keywords");
+
+	  return LEXICAL_ERROR;
+	}
+      else
+	TOK_PUSH_AND_RETURN (tok, FCN_HANDLE);
+    }
+
   // If we have a regular keyword, or a plot STYLE, return it.
   // Keywords can be followed by identifiers (TOK_RETURN handles
   // that).
 
-  int kw_token = is_keyword_token (tok);
-
   if (kw_token)
     {
       if (kw_token < 0)
@@ -2630,6 +2647,9 @@
   parsed_function_name = false;
   parsing_nested_function = 0;
 
+  // Not initiallly looking at a function handle.
+  looking_at_function_handle = 0;
+
   // Not parsing a function return or parameter list.
   looking_at_return_list = false;
   looking_at_parameter_list = false;
--- a/src/ov-fcn-handle.cc	Tue Aug 03 20:45:34 2004 +0000
+++ b/src/ov-fcn-handle.cc	Thu Aug 05 04:55:26 2004 +0000
@@ -38,6 +38,7 @@
 #include "ov-fcn-handle.h"
 #include "pr-output.h"
 #include "variables.h"
+#include "parse.h"
 
 DEFINE_OCTAVE_ALLOCATOR (octave_fcn_handle);
 
@@ -45,6 +46,57 @@
 				     "function handle",
 				     "function handle");
 
+octave_fcn_handle::octave_fcn_handle (const std::string& f,
+				      const string_vector& a, 
+				      const std::string& n)
+  : typ (fcn_inline), nm (n), iftext (f), ifargs (a) 
+{
+  // Find a function name that isn't already in the symbol table.
+
+  std::string fname = "__inline__";
+
+  while (symbol_exist (fname))
+    fname.append ("X");
+
+  // Form a string representing the function. 
+
+  OSSTREAM buf;
+
+  buf << "function __retval__ = " << fname << "(";
+
+  for (int i = 0; i < ifargs.length (); i++)
+    {
+      if (i > 0)
+	buf << ", ";
+
+      buf << ifargs(i);
+    }
+
+  buf << ")\n  __retval__ = " << iftext << ";\nendfunction" << OSSTREAM_ENDS;
+  
+  // Parse this function and create a user function.
+
+  octave_value eval_args (OSSTREAM_STR (buf)); 
+
+  feval ("eval", eval_args, 0);
+
+  OSSTREAM_FREEZE (buf);
+
+  octave_value tmp = lookup_function (fname);
+
+  if (tmp.is_function ())
+    {
+      fcn = tmp;
+
+      // XXX FIXME XXX -- probably shouldn't be directly altering the
+      // symbol table here.
+
+      fbi_sym_tab->clear_function (fname);
+    }
+  else
+    error ("inline: unable to define function");
+}
+
 octave_value_list
 octave_fcn_handle::subsref (const std::string& type,
 			    const std::list<octave_value_list>& idx,
@@ -65,8 +117,8 @@
     case '{':
     case '.':
       {
-	std::string nm = type_name ();
-	error ("%s cannot be indexed with %c", nm.c_str (), type[0]);
+	std::string typ_nm = type_name ();
+	error ("%s cannot be indexed with %c", typ_nm.c_str (), type[0]);
       }
       break;
 
@@ -94,8 +146,45 @@
 void
 octave_fcn_handle::print_raw (std::ostream& os, bool pr_as_read_syntax) const
 {
-  octave_print_internal (os, nm, pr_as_read_syntax,
-			 current_print_indent_level ());
+  if (is_inline ())
+    {
+      OSSTREAM buf;
+
+      if (nm.empty ())
+	buf << "@f(";
+      else
+	buf << nm << "(";
+
+      for (int i = 0; i < ifargs.length (); i++)
+	{
+	  if (i)
+	    buf << ", ";
+
+	  buf << ifargs(i);
+	}
+
+      buf << ") = " << iftext << OSSTREAM_ENDS;
+
+      octave_print_internal (os, OSSTREAM_STR (buf), pr_as_read_syntax,
+			     current_print_indent_level ());
+      OSSTREAM_FREEZE (buf);
+    }
+  else
+    octave_print_internal (os, nm, pr_as_read_syntax,
+			   current_print_indent_level ());
+}
+
+octave_value
+octave_fcn_handle::convert_to_str_internal (bool, bool) const
+{
+  octave_value retval;
+
+  if (is_inline ())
+    retval = octave_value (inline_fcn_text ());
+  else
+    error ("convert_to_str_internal: must be an inline function");
+
+  return retval;
 }
 
 octave_value
@@ -103,113 +192,232 @@
 {
   octave_value retval;
 
-  octave_function *f = lookup_function (nm);
+  octave_value f = lookup_function (nm);
 
-  if (f)
-    retval = octave_value (f, nm);
+  if (f.is_function ())
+    retval = octave_value (new octave_fcn_handle (f, nm));
   else
     error ("error creating function handle \"@%s\"", nm.c_str ());
 
   return retval;
 }
 
-DEFUN (functions, args, ,
+DEFUN (inline, args, ,
   "-*- texinfo -*-\n\
-@deftypefn {Built-in Function} {} functions (@var{fcn_handle})\n\
-Return a struct containing information about the function handle\n\
-@var{fcn_handle}.\n\
-@end deftypefn")
+@deftypefn {Built-in Function} {} inline (@var{str})\n\
+@deftypefnx {Built-in Function} {} inline (@var{str}, @var{arg1}, ...)\n\
+@deftypefnx {Built-in Function} {} inline (@var{str}, @var{n})\n\
+Define a function from a string @var{str}.\n\
+\n\
+Create an inline function.  Called with a single argument, the\n\
+function is assumed to have a single argument and will be defined\n\
+as the first isolated lower case character, except i or j.\n\
+\n\
+If the second and subsequent arguments are strings, they are the names of\n\
+the arguments of the function.\n\
+\n\
+If the second argument is an integer @var{n}, the arguments are\n\
+@code{\"x\"}, @code{\"P1\"}, @dots{}, @code{\"P@var{N}\"}.\n\
+@end deftypefn\n\
+@seealso{argnames, formula, vectorize}")
 {
   octave_value retval;
 
-  if (args.length () == 1)
+  int nargin = args.length ();
+
+  if (nargin > 0)
     {
-      octave_fcn_handle *fh = args(0).fcn_handle_value ();
+      std::string fun = args(0).string_value ();
 
       if (! error_state)
 	{
-	  octave_function *fcn = fh ? fh->function_value (true) : 0;
+	  string_vector fargs;
 
-	  if (fcn)
+	  if (nargin == 1)
 	    {
-	      Octave_map m;
+	      fargs.resize (1);
+
+	      // Find the first isolated string as the argument of the
+	      // function.
 
-	      std::string fh_nm = fh->name ();
+	      // XXX FIXME XXX -- use just "x" for now.
+	      fargs(0) = "x";
+	    }
+	  else if (nargin == 2 && args(1).is_numeric_type ())
+	    {
+	      int n = args(1).int_value ();
 
-	      m.assign ("function", fh_nm.substr (1));
+	      if (! error_state)
+		{
+		  if (n >= 0)
+		    {
+		      fargs.resize (n+1);
 
-	      if (fcn->is_nested_function ())
-		m.assign ("type", "subfunction");
-	      else
-		m.assign ("type", "simple");
-
-	      std::string nm = fcn->fcn_file_name ();
+		      fargs(0) = "x";
 
-	      if (nm.empty ())
-		m.assign ("file", "built-in function");
+		      for (int i = 1; i < n+1; i++)
+			{
+			  OSSTREAM buf;
+			  buf << "P" << i << OSSTREAM_ENDS;
+			  fargs(i) = OSSTREAM_STR (buf);
+			  OSSTREAM_FREEZE (buf);
+			}
+		    }
+		  else
+		    {
+		      error ("inline: numeric argument must be nonnegative");
+		      return retval;
+		    }
+		}
 	      else
-		m.assign ("file", nm);
-
-	      retval = m;
+		{
+		  error ("inline: expecting second argument to be an integer");
+		  return retval;
+		}
 	    }
 	  else
-	    error ("functions: invalid function handle object");
+	    {
+	      fargs.resize (nargin - 1);
+
+	      for (int i = 1; i < nargin; i++)
+		{
+		  std::string s = args(i).string_value ();
+
+		  if (! error_state)
+		    fargs(i-1) = s;
+		  else
+		    {
+		      error ("inline: expecting string arguments");
+		      return retval;
+		    }
+		}
+	    }
+
+	  retval = octave_value (new octave_fcn_handle (fun, fargs));
 	}
       else
-	error ("functions: argument must be a function handle object");
+	error ("inline: first argument must be a string");
     }
   else
-    print_usage ("functions");
+    print_usage ("inline");
 
   return retval;
 }
 
-DEFUN (func2str, args, ,
+DEFUN (formula, args, ,
   "-*- texinfo -*-\n\
-@deftypefn {Built-in Function} {} func2str (@var{fcn_handle})\n\
-Return a string containing the name of the function referenced by\n\
-the function handle @var{fcn_handle}.\n\
-@end deftypefn")
+@deftypefn {Built-in Function} {} formula (@var{fun})\n\
+Return a string representing the inline function @var{fun}.\n\
+@end deftypefn\n\
+@seealso{argnames, inline, vectorize}")
 {
   octave_value retval;
 
-  if (args.length () == 1)
-    {
-      octave_fcn_handle *fh = args(0).fcn_handle_value ();
+  int nargin = args.length ();
 
-      if (! error_state && fh)
-	{
-	  std::string fh_nm = fh->name ();
-	  retval = fh_nm.substr (1);
-	}
+  if (nargin == 1)
+    {
+      octave_fcn_handle* fn = args(0).fcn_handle_value (true);
+
+      if (fn && fn->is_inline ())
+	retval = octave_value (fn->inline_fcn_text ());
       else
-	error ("func2str: expecting valid function handle as first argument");
+	error ("formula: must be an inline function");
     }
   else
-    print_usage ("func2str");
+    print_usage ("formula");
 
   return retval;
 }
 
-DEFUN (str2func, args, ,
+DEFUN (argnames, args, ,
   "-*- texinfo -*-\n\
-@deftypefn {Built-in Function} {} str2func (@var{fcn_name})\n\
-Return a function handle constructed from the string @var{fcn_name}.\n\
-@end deftypefn")
+@deftypefn {Built-in Function} {} argnames (@var{fun})\n\
+Return a cell array of strings containing the names of the arguments\n\
+of the inline function @var{fun}.\n\
+@end deftypefn\n\
+@seealso{argnames, inline, formula, vectorize}")
 {
   octave_value retval;
 
-  if (args.length () == 1)
+  int nargin = args.length ();
+
+  if (nargin == 1)
     {
-      std::string nm = args(0).string_value ();
+      octave_fcn_handle *fn = args(0).fcn_handle_value (true);
+
+      if (fn && fn->is_inline ())
+	{
+	  string_vector t1 = fn->inline_fcn_arg_names ();
 
-      if (! error_state)
-	retval = make_fcn_handle (nm);
+	  Cell t2 (dim_vector (t1.length (), 1));
+
+	  for (int i = 0; i < t1.length (); i++)
+	    t2(i) = t1(i);
+
+	  retval = t2;
+	}
       else
-	error ("str2func: expecting string as first argument");
+	error ("argnames: argument must be an inline function");
     }
   else
-    print_usage ("str2func");
+    print_usage ("argnames");
+
+  return retval;
+}
+
+DEFUN (vectorize, args, ,
+  "-*- texinfo -*-\n\
+@deftypefn {Built-in Function} {} argnames (@var{fun})\n\
+Create a vectorized version of the inline function @var{fun}\n\
+by replacing all occurrences of @code{*}, @code{/}, etc., with\n\
+@code{.*}, @code{./}, etc.\n\
+@end deftypefn\n\
+@seealso{argnames, inline, formula, vectorize}")
+{
+  octave_value retval;
+
+  int nargin = args.length ();
+
+  if (nargin == 1)
+    {
+      octave_fcn_handle* old = args(0).fcn_handle_value (true);
+
+      if (old && old->is_inline ())
+	{
+	  std::string old_func = old->inline_fcn_text ();
+	  std::string new_func;
+
+	  size_t i = 0;
+
+	  while (i < old_func.length ())
+	    {
+	      std::string t1 = old_func.substr (i, 1);
+
+	      if (t1 == "*" || t1 == "/" || t1 == "\\" || t1 == "^")
+		{
+		  if (i && old_func.substr (i-1, 1) != ".")
+		    new_func.append (".");
+
+		  // Special case for ** operator.
+		  if (t1 == "*" && i < (old_func.length () - 1) 
+		      && old_func.substr (i+1, 1) == "*")
+		    {
+		      new_func.append ("*");
+		      i++;
+		    }
+		}
+	      new_func.append (t1);
+	      i++;
+	    }
+
+	  retval = octave_value (new octave_fcn_handle (new_func, old->inline_fcn_arg_names ()));
+	}
+      else
+	error ("vectorize: must be an inline function");
+    }
+  else
+    print_usage ("vectorize");
 
   return retval;
 }
--- a/src/ov-fcn-handle.h	Tue Aug 03 20:45:34 2004 +0000
+++ b/src/ov-fcn-handle.h	Thu Aug 05 04:55:26 2004 +0000
@@ -44,11 +44,16 @@
 octave_fcn_handle : public octave_base_value
 {
 public:
+  enum fcn_type { fcn_handle = 1, fcn_inline = 2 };
 
-  octave_fcn_handle (void) : fcn (0), nm () { }
+  octave_fcn_handle (void)
+    : typ (fcn_handle), fcn (), nm (), iftext (), ifargs () { }
 
-  octave_fcn_handle (octave_function *f, const std::string& n)
-    : fcn (f), nm (n) { }
+  octave_fcn_handle (const octave_value& f,  const std::string& n)
+    : typ (fcn_handle), fcn (f), nm (n), iftext (), ifargs () { }
+
+  octave_fcn_handle (const std::string& f, const string_vector& a, 
+		     const std::string& n = std::string ());
 
   ~octave_fcn_handle (void) { }
 
@@ -67,12 +72,21 @@
 
   bool is_function_handle (void) const { return true; }
 
-  octave_function *function_value (bool = false) { return fcn; }
+  octave_function *function_value (bool = false)
+    { return fcn.function_value (); }
+
+  std::string inline_fcn_name (void) const { return nm; }
 
-  std::string name (void) const { return nm; }
+  std::string inline_fcn_text (void) const { return iftext; }
+
+  string_vector inline_fcn_arg_names (void) const { return ifargs; }
+
+  bool is_inline (void) const { return (typ == fcn_inline); }
 
   octave_fcn_handle *fcn_handle_value (bool = false) { return this; }
 
+  octave_value convert_to_str_internal (bool, bool) const;
+
   void print (std::ostream& os, bool pr_as_read_syntax = false) const;
 
   void print_raw (std::ostream& os, bool pr_as_read_syntax = false) const;
@@ -89,11 +103,20 @@
 
   DECLARE_OV_TYPEID_FUNCTIONS_AND_DATA
 
+  // The type of function handle 
+  fcn_type typ;
+
   // The function we are handling.
-  octave_function *fcn;
+  octave_value fcn;
 
   // The name of the handle, including the "@".
   std::string nm;
+
+  // The expression of an inline function
+  std::string iftext;
+
+  // The args of an inline function
+  string_vector ifargs;
 };
 
 extern octave_value make_fcn_handle (const std::string& nm);
--- a/src/ov-usr-fcn.cc	Tue Aug 03 20:45:34 2004 +0000
+++ b/src/ov-usr-fcn.cc	Thu Aug 05 04:55:26 2004 +0000
@@ -606,7 +606,9 @@
 
       if (! error_state)
 	{
-	  octave_user_function *fcn = lookup_user_function (fname);
+	  octave_value fcn_val = lookup_user_function (fname);
+
+	  octave_user_function *fcn = fcn_val.user_function_value (true);
 
 	  if (fcn)
 	    {
@@ -676,7 +678,9 @@
 
       if (! error_state)
 	{
-	  octave_user_function *fcn = lookup_user_function (fname);
+	  octave_value fcn_val = lookup_user_function (fname);
+
+	  octave_user_function *fcn = fcn_val.user_function_value (true);
 
 	  if (fcn)
 	    {
--- a/src/ov.cc	Tue Aug 03 20:45:34 2004 +0000
+++ b/src/ov.cc	Thu Aug 05 04:55:26 2004 +0000
@@ -734,18 +734,6 @@
   rep->count = 1;
 }
 
-octave_value::octave_value (octave_function *f)
-  : rep (f)
-{
-  rep->count = 1;
-}
-
-octave_value::octave_value (octave_function *f, const std::string& nm)
-  : rep (new octave_fcn_handle (f, nm))
-{
-  rep->count = 1;
-}
-
 octave_value::octave_value (const octave_value_list& l, bool is_csl)
   : rep (0)
 {
--- a/src/ov.h	Tue Aug 03 20:45:34 2004 +0000
+++ b/src/ov.h	Thu Aug 05 04:55:26 2004 +0000
@@ -236,8 +236,6 @@
   octave_value (const Octave_map& m);
   octave_value (const octave_stream& s, int n);
   octave_value (const streamoff_array& off);
-  octave_value (octave_function *f);
-  octave_value (octave_function *f, const std::string &nm); // function handle
   octave_value (const octave_value_list& m, bool is_cs_list = false);
   octave_value (octave_value::magic_colon);
   octave_value (octave_value::all_va_args);
--- a/src/parse.y	Tue Aug 03 20:45:34 2004 +0000
+++ b/src/parse.y	Thu Aug 05 04:55:26 2004 +0000
@@ -672,6 +672,13 @@
 		  { $$ = $1; }
 		;
 
+fcn_handle	: '@' FCN_HANDLE
+		  {
+		    $$ = make_fcn_handle ($2);
+		    lexer_flags.looking_at_function_handle--;
+		  }
+		;
+
 fcn_handle	: FCN_HANDLE
 		  { $$ = make_fcn_handle ($1); }
 		;
--- a/src/variables.cc	Tue Aug 03 20:45:34 2004 +0000
+++ b/src/variables.cc	Thu Aug 05 04:55:26 2004 +0000
@@ -811,10 +811,10 @@
   return sym_rec;
 }
 
-octave_function *
+octave_value
 lookup_function (const std::string& nm)
 {
-  octave_function *retval = 0;
+  octave_value retval;
 
   symbol_record *sr = 0;
 
@@ -838,16 +838,16 @@
       octave_value v = sr->def ();
 
       if (v.is_function ())
-	retval = v.function_value ();
+	retval = v;
     }
 
   return retval;
 }
 
-octave_user_function *
+octave_value
 lookup_user_function (const std::string& nm)
 {
-  octave_user_function *retval = 0;
+  octave_value retval;
 
   symbol_record *sr = 0;
 
@@ -867,11 +867,7 @@
     }
 
   if (sr)
-    {
-      octave_value v = sr->def ();
-
-      retval = v.user_function_value (true);
-    }
+    retval = sr->def ();
 
   return retval;
 }
--- a/src/variables.h	Tue Aug 03 20:45:34 2004 +0000
+++ b/src/variables.h	Thu Aug 05 04:55:26 2004 +0000
@@ -75,19 +75,16 @@
 looks_like_struct (const std::string& text);
 
 extern int
-symbol_exist (const std::string& name,
-	      const std::string& type = std::string ());
+symbol_exist (const std::string& name, const std::string& type = "any");
 
 extern bool lookup (symbol_record *s, bool exec_script = true);
 
 extern symbol_record *
 lookup_by_name (const std::string& nm, bool exec_script = true);
 
-extern octave_function *
-lookup_function (const std::string& nm);
+extern octave_value lookup_function (const std::string& nm);
 
-extern octave_user_function *
-lookup_user_function (const std::string& nm);
+extern octave_value lookup_user_function (const std::string& nm);
 
 extern octave_value get_global_value (const std::string& nm);