Handler Statements
Run-time exceptions in HyperScript result from parsing and execution errors, timeouts, alarms, interrupts, and messages. HyperScript provides a set of handler statements that can be used to catch these exceptions and deal with the problem or condition that occurred. While some exceptions are caused by errors, many result from conditions that arise during normal program execution. For example, when an message is received it might need to be handled immediately.
The STATUS Variable
The HyperScript variable, STATUS, is set whenever an exception occurs. The value of STATUS indicates what condition triggered the exception. A handler method is any statement, or statement block, that follows the handler statement; it implicitly returns the value of STATUS. A handler method can examine the value of STATUS, and can alter the value of STATUS to control what happens after the handler completes.
The following table lists the condition values that STATUS can have, the type of exception that caused the condition, and the handler statement used to catch the exception.
| STATUS | Condition | Handler |
|---|---|---|
| $ACKNOWLEDGE | Success | N/A |
| %TIMEOUT | Timed out while blocking on query | on_timeout |
| %ALARM | Alarm has been triggered | on_alarm |
| %DEATH | Lifetime has expired | on_death |
| %MESSAGE | Message has been received | on_message |
| %INTERRUPT | An interrupt signal has occurred | on_interrupt |
| %PIPE | Connection (socket) error | on_pipe |
| %PARSE | Parse error | on_error |
| %EXPRESSION | Error in evaluating an expression | on_error |
| %BRANCH | Undefined label | on_error |
| %IDENTIFIER | Undefined identifier | on_error |
| %ARGUMENT | Invalid argument | on_error |
| %METHOD | Undefined method | on_error |
| %BOUNDS | Array bounds error, or divide-by-zero | on_error |
| %FILE | File open error | on_error |
| %IO | File I/O error | on_error |
| %EOF | End-of-file condition | on_error |
| %TARGET | Message target not found | on_error |
| %UNDEFINED | Undefined variable | on_error |
| %UNSUPPORTED | Unsupported message type | on_error |
| %REJECTED | Message rejected by target | on_error |
| %SQL | Error in SQL method | on_error |
| %SECS | Error in SECS message | on_error |
Note that the error condition codes all start with the character "%". These will, by convention, all test false. For example:
STATUS = "%TIMEOUT";
if ( !STATUS ) {
put ( "Timeout condition occurred" );
exit();
}
HyperScript States
When an exception occurs, HyperScript will be in one of four states:
- IDLE - Waiting to receive messages after calling idle
- QUERY - Waiting for a reply from query (sent message)
- PARSE - Parsing a program statement
- EXECUTE - Executing a method
The actions taken by the handler sometimes depend on the state (see specific handler statements below). The handler can change the state to control what happens after the handler completes.
On_error Statement
The on_error statement has the form:
on_error statement ;
When an unrecoverable error occurs, control is transferred unconditionally to the statement following on_error. This statement is typically a handler method. When the statement completes, control returns back to the statement following the point where the error occurred.
Once an error handler is used, it must be reestablished with the on_error statement to use it again. Typically, the on_error statement is called in the handler before returning.
on_error HANDLE_ERROR();
/* .
.
. */
HANDLE_ERROR() {
/* Handle an error
.
.
. */
/* Reestablish handler before returning. */
on_error HANDLE_ERROR();
return;
}
On_timeout Statement
The on_timeout statement has the form:
on_timeout statement;
A timeout condition can only occur when blocking on the query function. When a timeout condition occurs, control is transferred unconditionally to the statement following on_timeout. This statement is typically a handler method.
Once a timeout handler is used, it must be reestablished with the on_timeout statement to use it again. Typically, the on_timeout statement is called in the handler before returning.
When a timeout condition occurs, the value of STATUS becomes "%TIMEOUT". If the handler changes the value of STATUS to a success value such as "$ACKNOWLEDGE", then upon returning from the handler query will continue waiting for the reply message, using the previously specified timeout. If the STATUS value remains as "%TIMEOUT", or is changed to any other non-success value, query will fail and return the value of STATUS.
The timeout value is set using the timeout function. For example:
timeout ( 20 ); /* Set query timeout to 20 seconds */
on_timeout HANDLE_TIMEOUT ();
query ( "target", "method" ); /* Execute method on the target */
if ( STATUS == "%TIMEOUT" ) {
/* query timed out
.
.
. */
}
HANDLE_TIMEOUT() {
/* Handle the query timeout condition
.
.
. */
/* Reestablish handler before returning. */
on_timeout HANDLE_TIMEOUT ();
/* .
.
. */
/* Maybe let query continue waiting for reply */
if ( retryQuery ) STATUS = "$ACKNOWLEDGE";
return;
}
On_alarm Statement
The on_alarm statement has the form:
on_alarm statement ;
When an alarm condition occurs, control is transferred unconditionally to the statement following on_alarm. This statement is typically a handler method. When the statement completes, control returns back to the statement following the point where the alarm occurred. An alarm is set using the alarm function.
Once an alarm handler is used, it must be reestablished with the on_alarm statement to use it again. Typically, the on_alarm statement is called in the handler before returning.
When an alarm condition occurs, the value of STATUS becomes "%ALARM". If the HyperScript program was in the IDLE state when the alarm occurred, a return from the alarm handler continues in the IDLE state. If the HyperScript program was in the EXECUTE state, control returns to the point where the alarm occurred, with no net effect. If the HyperScript program was in the QUERY state, control returns to the query function. The query function either fails and returns the value of STATUS (i.e. "%ALARM"), or continues to wait for a reply message if STATUS was changed to a success value such as "$ACKNOWLEDGE".
On_interrupt Statement
The on_interrupt statement has the form:
on_interrupt statement ;
When an interrupt condition occurs, for example, a ^C signal, control is transferred unconditionally to the statement following on_interrupt. This statement is typically a handler method.
Once an interrupt handler is used, it must be reestablished with the on_interrupt statement to use it again. Typically, the on_interrupt statement is called in the handler before returning.
When the handler statement completes, control returns to the statement following the point where the interrupt occurred. If the HyperScript program was in the IDLE state, control returns to the IDLE state. If the HyperScript program was in the EXECUTE state, control returns to the point that was interrupted, with no net effect. If the HyperScript program was in the QUERY state, control returns to the query function. The query function either fails and returns the value of STATUS (i.e.: "%INTERRUPT"), or continues to wait for a reply message if STATUS was changed to a success value such as "$ACKNOWLEDGE".
On_pipe Statement
The on_pipe statement has the form:
on_pipe statement ;
When a socket (pipe) error occurs...
On_death Statement
The on_death statement has the form:
on_death statement ;
A death condition occurs when the program's lifetime expires (specified by the lifetime function). Control is transferred unconditionally to the statement following on_death. This statement is typically a handler method.
Once a death handler is used, it must be reestablished with the on_death statement to use it again. Typically, the on_death statement is called in the handler before returning.
When the handler statement completes the instance will exit. To prevent death, the handler must reinstate a new lifetime interval using the lifetime function before returning. If the HyperScript program was in the IDLE state, control returns to the IDLE state. If the HyperScript program was in the EXECUTE state, control returns to the point that was interrupted by the death condition, with no net effect.
If the HyperScript program was in the QUERY state, then control returns to the query function. The query function either fails and returns the value of STATUS (i.e.: "%DEATH") or continues to wait for a reply message if STATUS was changed to a success value such as "$ACKNOWLEDGE".
On_message Statement
The on_message statement has the form:
on_message statement ;
When an incoming message specifies a defined and enabled method in the HyperScript program, control is transferred unconditionally to the statement following on_message. This statement is typically a handler method.
Once a message handler is used, it must be reestablished with the on_message statement to use it again. Typically, the on_message statement is called in the handler before returning.
The HyperScript program must return to the IDLE state to execute the message. If the HyperScript program was already in the IDLE state, the handler can simply return. To prevent the message from executing, the method can be disabled using the disable statement before returning to the IDLE state.
When a message interrupts a HyperScript program in the QUERY state, the handler can do one of three things:
- It can return to the query function, which will fail with a return value of "%TIMEOUT".
- It can ignore the incoming message by changing the value of STATUS from "%MESSAGE" to "$ACKNOWLEDGE" and returning. The query function will continue to wait for a reply. If another message arrives it overrides the previous one and another message exception occurs.
- It can execute the idle function, which will abort the query function and put the HyperScript program into the IDLE state, where it will execute the incoming message.
- It can examine the method, mode, and sender of the incoming message using the method, mode, and sender functions. This is useful when more than one method is enabled for incoming messages; the handler can look at the message before responding.
The following example illustrates a typical message handling situation:
enable ABORT; /* Enable a method to handle ABORT */
enable DISCONNECT; /* Enable a method to handle DISCONNECT */
enable SETUP; /* Enable a method to handle SETUP */
on_message HANDLE_MESSAGE();
query ( "target", "method" ); /* Execute method on the target */
if ( STATUS == "%MESSAGE" ) ABORT();
/* Successful query
.
.
. */
HANDLE_MESSAGE()
{
/* Handle an incoming message condition. */
if ( method() == "DISCONNECT" || method() == "ABORT" )
/* Execute these methods immediately */
idle();
else if ( method() == "SETUP" )
/* Not accepting SETUP right now, resume the query */
STATUS = "$ACKNOWLEDGE";
else {
/* Some other method requested. Let the query fail */
put ( "Received unexpected method " + method() );
return;
}
Note:
An incoming message will not interrupt a HyperScript program in the EXECUTE state. The HyperScript program must be in the IDLE or QUERY state before the interrupting method is actually received.