[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\
- Re: rethrow?,
David Bateman <=