Many intrinsic functions signal errors in the event of failure.
User defined functions may also generate an error condition via the
error
function. Depending upon the severity of the error, it
can be caught and cleared using a construct called an
error-block.
When the interpreter encounters a recoverable run-time error, it will return to top-level by unwinding its function call stack. Any error-blocks that it encounters as part of this unwinding process will get executed. Errors such as syntax errors and memory allocation errors are not recoverable, and error-blocks will not get executed when such errors are encountered.
An error-block is defined using the syntax
ERROR_BLOCK { statement-list }
where statement-list represents a list of statements that
comprise the error-block. A simple example of an error-block is
define simple (a)
{
ERROR_BLOCK { message ("error-block executed"); }
if (a) error ("Triggering Error");
message ("hello");
}
Executing this function via simple(0)
will result in the
message "hello"
. However, calling it using simple(1)
will generate an error that will be caught, but not cleared, by
the error-block and the "error-block executed"
message will
result.
Error-blocks are never executed unless triggered by an error. The
only exception to this is when the user explicitly indicates that
the error-block in scope should execute. This is indicated by the
special keyword EXECUTE_ERROR_BLOCK
. For example,
simple
could be recoded as
define simple (a)
{
variable err_string = "error-block executed";
ERROR_BLOCK { message (err_string); }
if (a) error ("Triggering Error");
err_string = "hello";
EXECUTE_ERROR_BLOCK;
}
Please note that EXECUTE_ERROR_BLOCK
does not initiate an
error condition; it simply causes the error-block to be executed
and control will pass onto the next statement following the
EXECUTE_ERROR_BLOCK
statement.
Once an error has been caught by an error-block, the error can be cleared
by the _clear_error
function. After the error has been cleared,
execution will resume at the next statement at the level of the error block
following the statement that generated the error. For example, consider:
define make_error ()
{
error ("Error condition created.");
message ("This statement is not executed.");
}
define test ()
{
ERROR_BLOCK
{
_clear_error ();
}
make_error ();
message ("error cleared.");
}
Calling test
will trigger an error in the make_error
function, but will get cleared in the test
function. The
call-stack will unwind from make_error
back into test
where the error-block will get executed. As a result, execution
resumes after the statement that makes the call to make_error
since this statement is at the same level as the error-block that
cleared the error.
Here is another example that illustrates how multiple error-blocks work:
define example ()
{
variable n = 0, s = "";
variable str;
ERROR_BLOCK {
str = sprintf ("s=%s,n=%d", s, n);
_clear_error ();
}
forever
{
ERROR_BLOCK {
s += "0";
_clear_error ();
}
if (n == 0) error ("");
ERROR_BLOCK {
s += "1";
}
if (n == 1) error ("");
n++;
}
return str;
}
Here, three error-blocks have been declared. One has been declared
outside the forever
loop and the other two have been declared
inside the forever
loop. Each time through the loop, the variable
n
is incremented and a different error-block is triggered. The
error-block that gets triggered is the last one encountered, since
that will be the one in scope. On the first time through the loop,
n
will be zero and the first error-block in the loop will get
executed. This error block clears the error and execution resumes
following the if
statement that triggered the error. The
variable n
will get incremented to 1
and, on the
second cycle through the loop the second if
statement
will trigger an error causing the second error-block to execute.
This time, the error is not cleared and the call-stack unwinds out
of the forever
loop, at which point the error-block outside
the loop is in scope, causing it to execute. This error-block
prints out the values of the variables s
and n
. It
will clear the error and execution resumes on the statement
following the forever
loop. The result of this
complicated series of events is that the function will return the
string "s=01,n=1"
.