Next Previous Contents

12. Error Handling

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.

12.1 Error-Blocks

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.

12.2 Clearing Errors

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".


Next Previous Contents