octave-maintainers
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: rethrow?


From: David Bateman
Subject: Re: rethrow?
Date: Thu, 01 Feb 2007 19:25:51 +0100
User-agent: Thunderbird 1.5.0.7 (X11/20060921)

John W. Eaton wrote:
> On 26-Jan-2007, Paul Kienzle wrote:
>
> | 
> | On Jan 26, 2007, at 3:50 AM, David Bateman wrote:
> | 
> | > I can't remember early versions of matlab having this function, however
> | > there seems to be a useful function called "rethrow" that can be used 
> | > in
> | > conjunction with try/catch like
> | >
> | >         try
> | >             do_something
> | >         catch
> | >             do_cleanup
> | >             rethrow(lasterror)
> | >         end
> | >
> | > It seems like it wouldn't be hard to add this, with the only complexity
> | > to me being the format of the variable lasterror.
> | 
> | I think I already do this somewhere:
> | 
> |    try
> |      something
> |    catch
> |      fixup
> |      error(lasterror)
> |    end
>
> This has a similar effect to rethrow but doesn't it make the error
> appear to have happened at the location inside the catch block?  With
> rethrow, I assume the information about the location of the error
> remains the original call to error.  If so, then I think properly
> implementing rethrow requires more than just making it an alias for
> error.
>
> jwe
>
>   

How about something like the attached patch? One issue with the attached
patch is it won't give exactly the same error message when rethrown..
For exampl

octave:1>sind
Invalid call to sind.  Correct usage is:

 -- Function File:  sind (X)


Additional help for built-in functions and operators is
available in the on-line version of the manual.  Use the command
`doc <topic>' to search the manual index.

Help and information about Octave is also available on the WWW
at http://www.octave.org and via the address@hidden
mailing list.

error: evaluating if command near line 25, column 3
error: called from `sind' in file
`/opt/octave-2.9/share/octave/2.9.9+/m/elfun/sind.m'
octave:1> try, sind(); catch, rethrow(lasterror()); end
error:
Invalid call to sind.  Correct usage is:

 -- Function File:  sind (X)


Additional help for built-in functions and operators is
available in the on-line version of the manual.  Use the command
`doc <topic>' to search the manual index.

Help and information about Octave is also available on the WWW
at http://www.octave.org and via the address@hidden
mailing list.

error: called from `sind' in file
/opt/octave-2.9/share/octave/2.9.9+/m/elfun/sind.m near line 26, column 5:
octave:2>

As you see the "evaluating if ..." part of the error message is not
reproduced, although the line and column numbers are.. If this is a
problem, it will be much harder to implement this feature as you'd have
to hook into all of the error traceback code in all of the octave_value
classes. Is this worth it?

Regards
David


*** ./src/error.cc.orig31       2006-09-26 17:43:44.000000000 +0200
--- ./src/error.cc      2007-02-01 18:26:55.505934552 +0100
***************
*** 85,90 ****
--- 85,102 ----
  // The last error message id.
  static std::string Vlast_error_id;
  
+ // The last file in which an error occured
+ static std::string Vlast_error_file;
+ 
+ // The last function in which an error occured
+ static std::string Vlast_error_name;
+ 
+ // The last line in a function at which an error occured
+ static int Vlast_error_line = -1;
+ 
+ // The last column in a function at which an error occured
+ static int Vlast_error_column = -1;
+ 
  // Current error state.
  //
  // Valid values:
***************
*** 214,219 ****
--- 226,250 ----
  
        Vlast_error_id = id;
        Vlast_error_message = msg_string;
+ 
+       Vlast_error_line = -1;
+       Vlast_error_column = -1;
+       Vlast_error_name = std::string ();
+       Vlast_error_file = std::string ();
+ 
+       if (curr_statement)
+       {
+         octave_function *fcn
+           = octave_call_stack::caller_user_script_or_function ();
+ 
+         if (fcn)
+           {
+             Vlast_error_file = fcn->fcn_file_name ();
+             Vlast_error_name = fcn->name();
+             Vlast_error_line = curr_statement->line ();
+             Vlast_error_column = curr_statement->column ();
+           }
+       }
      }
  
    if (buffer_error_messages)
***************
*** 631,636 ****
--- 662,676 ----
  }
  
  void
+ rethrow_error (const char *id, const char *fmt, ...)
+ {
+   va_list args;
+   va_start (args, fmt);
+   error_1 (std::cerr, "error", id, fmt, args);
+   va_end (args);
+ }
+ 
+ void
  panic (const char *fmt, ...)
  {
    va_list args;
***************
*** 721,726 ****
--- 761,885 ----
    return retval;
  }
  
+ DEFUN (rethrow, args, ,
+   "-*- texinfo -*-\n\
+ @deftypefn {Built-in Function} {} rethrow (@var{err})\n\
+ Reissues a previous error as defined by @var{err}. @var{err} is a structure\n\
+ that must contain at least the 'message' and 'identifier' fields. @var{err}\n\
+ can also contain a field 'stack' that gives information on the assumed\n\
+ location of the error. Typically @var{err} is returned from\n\
+ @code{lasterror}.\n\
+ @seealso{lasterror, lasterr, error}\n\
+ @end deftypefn")
+ {
+   octave_value retval;
+   int nargin = args.length();
+ 
+   if (nargin != 1)
+     print_usage();
+   else
+     {
+       Octave_map err = args(0).map_value();
+ 
+       if (!error_state)
+       {
+         if (err.contains("message") && err.contains("identifier"))
+           {
+             std::string msg = err.contents("message")(0).string_value();
+             std::string id = err.contents("identifier")(0).string_value();
+             int len = msg.length();
+             std::string file;
+             std::string nm;
+             int l = -1;
+             int c = -1;
+ 
+             if (err.contains("stack"))
+               {
+                 Octave_map err_stack = err.contents("stack")(0).map_value();
+ 
+                 if (err_stack.contains("file"))
+                   file = err_stack.contents("file")(0).string_value();
+                 if (err_stack.contains("name"))
+                   nm = err_stack.contents("name")(0).string_value();
+                 if (err_stack.contains("line"))
+                   l = err_stack.contents("line")(0).nint_value();
+                 if (err_stack.contains("column"))
+                   c = err_stack.contents("column")(0).nint_value();
+               }
+ 
+             // Ugh.
+             char *tmp_msg = strsave (msg.c_str());
+             if (tmp_msg[len-1] == '\n')
+               {
+                 if (len > 1)
+                   {
+                     tmp_msg[len - 1] = '\0';
+                     rethrow_error (id.c_str(), "%s\n", tmp_msg);
+                   }
+               }
+             else
+               rethrow_error (id.c_str(), "%s", tmp_msg);
+             delete [] tmp_msg;
+ 
+             // FIXME: Need to restore the stack as rethrow_error sets it?
+             Vlast_error_file = file;
+             Vlast_error_name = nm;
+             Vlast_error_line = l;
+             Vlast_error_column = c;
+ 
+             if (err.contains("stack"))
+               {
+                 if (file.empty ())
+                   {
+                     if (nm.empty ())
+                       {
+                         if (l > 0)
+                           if (c > 0)
+                             pr_where_1 ("error: near line %d, column %d", 
+                                         l, c);
+                           else
+                             pr_where_1 ("error: near line %d", l );
+                       }
+                     else
+                       {
+                         if (l > 0)
+                           if (c > 0)
+                             pr_where_1 ("error: called from `%s' near line 
%d, column %d", 
+                                         nm.c_str(), l, c);
+                           else
+                             pr_where_1 ("error: called from `%d' near line 
%d", nm.c_str(), l );
+                       }
+                   }
+                 else
+                   {
+                     if (nm.empty ())
+                       {
+                         if (l > 0)
+                           if (c > 0)
+                             pr_where_1 ("error: in file %s near line %d, 
column %d", 
+                                         file.c_str(), l, c);
+                           else
+                             pr_where_1 ("error: in file %s near line %d", 
file.c_str(), l );
+                       }
+                     else
+                       {
+                         if (l > 0)
+                           if (c > 0)
+                             pr_where_1 ("error: called from `%s' in file %s 
near line %d, column %d", 
+                                         nm.c_str(), file.c_str(), l, c);
+                           else
+                             pr_where_1 ("error: called from `%d' in file %s 
near line %d", nm.c_str(), file.c_str(), l );
+                       }
+                   }
+               }
+           }
+         else
+           error ("rethrow: structure must contain the fields 'message and 
'identifier'");
+       }
+     }
+   return retval;
+ }
+ 
  DEFUN (error, args, ,
    "-*- texinfo -*-\n\
  @deftypefn {Built-in Function} {} error (@var{template}, @dots{})\n\
***************
*** 1110,1115 ****
--- 1269,1444 ----
    disable_warning ("Octave:variable-switch-label");
  }
  
+ DEFUN (lasterror, args, ,
+   "-*- texinfo -*-\n\
+ @deftypefn {Built-in Function} address@hidden =} lasterror (@var{err})\n\
+ @deftypefnx {Built-in Function} {} lasterror ('reset')\n\
+ Returns or sets the last error message. Called without any arguments\n\
+ returns a structure containing the last error message, as well as other\n\
+ information related to this error. The elements of this structure are:\n\
+ \n\
+ @table @asis\n\
+ @item 'message'\n\
+ The text of the last error message\n\
+ @item 'identifier'\n\
+ The message identifier of this error message\n\
+ @item 'stack'\n\
+ A structure containing information on where the message occured. This might\n\
+ be an empty structure if this in the case where this information can not\n\
+ be obtained. The fields of this structure are:\n\
+ \n\
+ @table @asis\n\
+ @item 'file'\n\
+ The name of the file where the error occurred\n\
+ @item 'name'\n\
+ The name of function in which the error occured\n\
+ @item 'line'\n\
+ The line number at which the error occured\n\
+ @item 'column'\n\
+ An optional field with the column number at which the error occurred\n\
+ @end table\n\
+ @end table\n\
+ \n\
+ The @var{err} structure may also be passed to @code{lasterror} to set the\n\
+ information about the last error. The only constraint on @var{err} in that\n\
+ case is that it is a scalar structure. Any fields of @var{err} that match\n\
+ the above are set to the value passed in @var{err}, while other fields are\n\
+ set to their default values.\n\
+ \n\
+ If @code{lasterror} is called with the argument 'reset', all values take\n\
+ their default values.\n\
+ @end deftypefn")
+ {
+   octave_value retval;
+   int nargin = args.length();
+ 
+   if (nargin < 2)
+     {
+       Octave_map err;
+ 
+       err.assign ("message", Vlast_error_message);
+       err.assign ("identifier", Vlast_error_id);
+ 
+       if (! (Vlast_error_file.empty() && Vlast_error_name.empty() &&
+            Vlast_error_line < 0 && Vlast_error_column < 0))
+       {
+         Octave_map err_stack;
+ 
+         err_stack.assign ("file", Vlast_error_file);
+         err_stack.assign ("name", Vlast_error_name);
+         err_stack.assign ("line", Vlast_error_line);
+         err_stack.assign ("column", Vlast_error_column);
+ 
+         err.assign ("stack", octave_value (err_stack));
+       }
+       else
+       {
+         string_vector sv(4);
+         sv[0] = "file"; 
+         sv[1] = "name";
+         sv[2] = "line";
+         sv[3] = "column";
+         err.assign ("stack", octave_value (Octave_map (dim_vector (0,1), 
+                                                        sv)));
+       }
+ 
+       if (nargin == 1)
+       {
+         if (args(0).is_string())
+           {
+             if (args(0).string_value() == "reset")
+               {
+                 Vlast_error_message = std::string();
+                 Vlast_error_id = std::string();
+                 Vlast_error_file = std::string();
+                 Vlast_error_name = std::string();
+                 Vlast_error_line = -1;
+                 Vlast_error_column = -1;
+               }
+             else
+               error("lasterror: unrecognized string argument");
+           }
+         else if (args(0).is_map ())
+           {
+             Octave_map new_err = args(0).map_value();
+             std::string new_error_message;
+             std::string new_error_id;
+             std::string new_error_file;
+             std::string new_error_name;
+             int new_error_line = -1;
+             int new_error_column = -1;
+ 
+             if (!error_state && new_err.contains("message"))
+               {
+                 const std::string tmp = 
+                   new_err.contents("message")(0).string_value();
+                 new_error_message = tmp;
+               }
+ 
+             if (!error_state && new_err.contains("identifier"))
+               {
+                 const std::string tmp = 
+                   new_err.contents("identifier")(0).string_value();
+                 new_error_id = tmp;
+               }
+ 
+             if (!error_state && new_err.contains("stack"))
+               {
+                 Octave_map new_err_stack = 
+                   new_err.contents("identifier")(0).map_value();
+ 
+                 if (!error_state && new_err_stack.contains("file"))
+                   {
+                     const std::string tmp = 
+                       new_err_stack.contents("file")(0).string_value();
+                     new_error_file = tmp;
+                   }
+ 
+                 if (!error_state && new_err_stack.contains("name"))
+                   {
+                     const std::string tmp = 
+                       new_err_stack.contents("name")(0).string_value();
+                     new_error_name = tmp;
+                   }
+ 
+                 if (!error_state && new_err_stack.contains("line"))
+                   {
+                     const int tmp = 
+                       new_err_stack.contents("line")(0).nint_value();
+                     new_error_line = tmp;
+                   }
+                 
+                 if (!error_state && new_err_stack.contains("column"))
+                   {
+                     const int tmp = 
+                       new_err_stack.contents("column")(0).nint_value();
+                     new_error_column = tmp;
+                   }
+               }
+ 
+             if (! error_state)
+               {
+                 Vlast_error_message = new_error_message;
+                 Vlast_error_id = new_error_id;
+                 Vlast_error_file = new_error_file;
+                 Vlast_error_name = new_error_name;
+                 Vlast_error_line = new_error_line;
+                 Vlast_error_column = new_error_column;
+               }
+           }
+         else
+           error ("lasterror: argument must be a structure or a string");
+       }
+ 
+       if (!error_state)
+       retval = err;
+     }
+   else
+     print_usage ();
+ 
+   return retval;  
+ }
+ 
  DEFUN (lasterr, args, nargout,
    "-*- texinfo -*-\n\
  @deftypefn {Built-in Function} address@hidden, @var{msgid}] =} lasterr 
(@var{msg}, @var{msgid})\n\

reply via email to

[Prev in Thread] Current Thread [Next in Thread]