Exception handling
Through the ON_ERROR_DO statement a powerful Exception handling mechanism is offered. The SYNTAX is the same as for a compound statement except that ON_ERROR_DO/END_ON_ERROR_DO is used instead of BEGIN/END.
ON_ERROR_DO
(* statements *)
END_ON_ERROR_DO;
Any number of ON_ERROR_DO statements within the scope one declaration is legal, but ON_ERROR_DO statements cannot be nested. ON_ERROR_DO statements can be declared within the scope of other statements e.g. FROM,REPEAT,COMPOUND,IF,CASE and WHEN. ON_ERROR_DO statements are invisible from outside the scope in which they are defined.
Exception instance.
There exists one built in entity instance (object) that carries the exception information as lined out in the definition below.
ENTITY xpxException;
errCode : INTEGER;
errMessage : OPTIONAL STRING;
userCode : OPTIONAL INTEGER;
userMessage : OPTIONAL STRING;
functionName : STRING;
lineNumber : INTEGER;
END_ENTITY;
The built in constant xpxExceptionId identifies the xpxException instance, and the attributes are accessed in the same way as for any other instance, as shown below.
xpxPrintf('\nError: %ld at line: %ld', xpxExceptionId.errCode, xpxExceptionId.lineNumber);
An exception is raised whenever an error is detected by the EDMexpressVM, or whenever the xpxThrow procedure is explicitly invoked.
PROCEDURE xpxThrow( returnValue : GENERIC;
errCode : INTEGER;
userCode : INTEGER;
lineNumber : INTEGER;
errMessage : STRING;
userMessage : STRING;
functionName : STRING);
Exception characteristics.
Whenever an exception is raised, and there is no ON_ERROR_DO catch block in scope, the exception is ignored.
Whenever an exception is raised and there is one or more ON_ERROR_DO catch blocks in scope, the statements within the closest ON_ERROR_DO catch block are executed, before the control is passed to statement after the one where the exception was raised. That is, exceptions are not automatically propagated to the calling scope. In stead propagation is optionally performed by invoking the xpxThrow procedure as explained below
Invocation of the xpxThrow procedure from within an ON_ERROR_DO catch block, passes the control to the closest ON_ERROR_DO block in the calling scope (function, map, statements, etc.). If there is no ON_ERROR_DO catch block in the scope of the call, the xpxThrow procedure works like a RETURN statement with the xpxThrow argument 'returnValue' as the function value.
Invocation of the xpxThrow procedure from outside an ON_ERROR_DO catch block will enter the closest ON_ERROR_DO block in scope, if any. If there exists no ON_ERROR_DO block in scope, a call to xpxThrow has no effect.
The occurrence of an ESCAPE statement, or invocation of the xpxEscapeScope function, within the scope of an ON_ERROR_DO catch block, will transfer the control to the statement after which the exception was raised, whereas the occurrence of a RETURN statement will transfer the control to the calling scope.
The xpfGetStackLevels and xpxPrintStack functions can be used to dump the call stack. These functions are applicable wherever a function call is legal, but are probably most useful within the scope of an ON_ERROR_DO catch block. It probably makes sense to make use of a global variable to keep track of whether the stack has already been dumped or not. In this way one avoids to dump the stack at each level when one is crawling out of an exception.
Example:
In this example there are three possible scenarios in connection with the xpxDeleteModelBN function.
- If the model 'MYMODEL' exists, it will be deleted.
- If it does not exist, ‘Warning: MYMODEL does not exist’, will be printed.
- If an unforeseen exception is thrown by the EDMexpressVM , essential information about the exception and the stack is printed, and the exception is propagated to the calling level.
ON_ERROR_DO
IF(xpxExceptionId.errCode <> xpxENOMODEL) THEN
xpxPrintf('\nException raised at line %d in %s',
xpxExceptionId.lineNumber,xpxExceptionId.functionName);
xpxPrintf('\n%s',xpfGetErrorText(xpxExceptionId.errCode));
status := xpxPrintStack(xpfGetStackLevels(),xpfGetStackLevels(),'',
XPXPRINT_FUNCTIONS_ARGUMENTS ~|
XPXPRINT_LOCAL_VARIABLES ~|
XPXPRINT_GLOBAL_VARIABLES ~|
XPXPRINT_TO_STDOUT);
xpxExceptionId.userCode := 1;
xpxThrow;
END_IF;
xpxPrintf('\nWarning: MYMODEL does not exist');
END_ON_ERROR_DO;
status := xpxOpenRepositoryBN('DataRepository',repid);
xpxDeleteModelBN(0,'MYMODEL');