Modula-2 Reloaded

A Modern Typesafe & Literate Programming Notation

Site Menu

Project

Specification

Implementation

Recommendations

Reference

Needs Updating

Work in Progress

Wastebasket

Wiki Manual

edit SideBar

Exception Handling Using Dispatch Table

WiP.ExceptionHandlingUsingDispatchTable History

Hide minor edits - Show changes to output

2010-04-23 11:30 by benjk -
Changed lines 98-100 from:
(* Exception handling library *)

to:
(* Library based Exception Handling *)


(* Dispatch Table *)

Added lines 105-106:
(* Exception Type *)
Added lines 109-110:
(* Exceotion Handler Type *)
Changed lines 114-120 from:
(* null key *)

CONST [NIL] nullKey = 0C;


(* allocator
*)
to:
(* Allocator *)
Changed lines 117-148 from:


(* accessor *)

PROCEDURE [.] handlerForException ( dispatchTable : Exceptions; e : Exception; VAR found : BOOLEAN ) : Handler;
(* Searches for exception e in dispatch table, if found passes TRUE in found and returns its handler,
  otherwise passes FALSE
*)


(* mutators *)

PROCEDURE [!] pushHandler ( dispatchTable : Exceptions; e : Exception; handler : Handler );
(* Pushes a new handler onto the handler stack for exception e in dispatchTable *)

PROCEDURE [-] popHandler ( dispatchTable : Exceptions
; e : Exception );
(* Removes the topmost handler from the handler stack for exception e in dispatchTable *)


(* membership test *)

PROCEDURE [IN] handlerExists ( dispatchTable : Exceptions; e : Exception ) : BOOLEAN;
(* Returns TRUE if a handler exists for exception e in dispatchTable, otherwise returns FALSE *)


(* raise an exception *)

PROCEDURE raise ( dispatchTable :
Exceptions; e : Exception );
(* Raises exception e by calling the topmost handler for e in dispatchTable *)


(*
counter *)
to:
(* Allocates and initialises a new dispatch table and passes it back in
 
  <dispatchTable>. Returns NIL if the allocation failed. This procedure
  is bound to pervasive procedure NEW for arguments of type Exceptions.
*)


(* Accessor *)

PROCEDURE [.] handlerForException ( dispatchTable : Exceptions;
               e : Exception; VAR found : BOOLEAN ) : Handler;
(* Searches for exception <e> in <dispatchTable>. If it is found then TRUE is
  passed back in <found> and the topmost handler of <e> is returned, otherwise
   FALSE is passed back in <found> and NIL is returned. This function is bound
  to the array operator [ ] for rvalues of type
Exceptions.*)


(* Mutators *
)

PROCEDURE [!] AddHandler ( dispatchTable : Exceptions;
                e : Exception; handler : Handler );
(* Adds a new exception handler on top of the handler stack for exception <e>
  in <dispatchTable>. If NIL is passed in for <handler> then the topmost
  handler for <e> is removed from <dispatchTable>. This procedure is
  bound to the array operator [ ] for lvalues of type Exceptions. *)


(* Membership test *)

PROCEDURE [IN] handlerExists ( dispatchTable : Exceptions;
                                          e : Exception ) : BOOLEAN;
(* Returns TRUE if a handler exists for exception <e> in <dispatchTable>,
  returns FALSE otherwise. This function is bound to the IN operator
  for type Exceptions. *)


(* Raise an exception *)

PROCEDURE Raise ( dispatchTable : Exceptions; e : Exception );
(* Raises exception e by retrieving and calling the topmost handler for <e>
  in <dispatchTable>. When the handler returns, the procedure will initiate
  the runtime system's termination sequence to terminate the program. *)


(* Resume from exception *)

PROCEDURE Resume;
(* Returns control to the procedure that raised the current exception. This
  procedure is used to prevent procedure Raise to initiate termination. *)


(* Exception
counter *)
Changed lines 169-181 from:
(* Returns the number of exceptions defined in dispatchTable *)


(* iterator *)

PROCEDURE [FOR] nextException ( dispatchTable : Exceptions; VAR e : Exception; VAR handler : Handler
);
(* Finds the successor of e and passes its exception/handler pair back in exception and handler.
  If the null key is passed in then the first exception/handler pair is passed back.
 
  If no successor is found then the null key is passed back in e and handler is undefined. *)


(* destructor
*)
to:
(* Returns the number of exceptions defined in <dispatchTable>. This function
  is bound to pervasive function COUNT for type Exceptions. *)


(* Iterator *
)

PROCEDURE [FOR] nextException ( dispatchTable : Exceptions;
       
         VAR e : Exception; VAR handler : Handler );
(* Finds the
successor of <e> and passes its exception/handler pair back in
   <exception> and <handler>. If the null key is passed in then the first
  exception/handler pair is passed back. If no successor is found then the
  null key is passed back in <e> and <handler> is undefined. This procedure
  is bound to the FOR .. IN iterator for type Exceptions. *)


(* Destructor
*)
Changed lines 187-188 from:
(* Deallocates dispatchTable and passes NIL back *)
to:
(* Deallocates <dispatchTable> and passes NIL back. This procedure is bound
  to pervasive procedure DISPOSE for arguments of type Exceptions.
*)
2010-04-16 11:12 by benjk -
Added lines 13-14:

All these operations can be implemented without any language support. However, depending on the desired semantics, the raise operation may need to return to the caller's caller. If that is desired, then a primitive in module @@SYSTEM@@ would be useful to allow the return of control to the caller's caller.
2010-04-14 16:39 by benjk -
Changed line 92 from:
The following shows an example library interface:
to:
The following shows the interface for the exception library:
2010-04-14 16:36 by benjk -
Changed line 63 from:
       IF barError THEN Exceptions.raise(exceptions, "BarError"); (* or here? *) END;
to:
       IF barError THEN Exceptions.raise(exceptions, "BarError"); (* and here? *) END;
2010-04-14 16:36 by benjk -
Changed lines 62-63 from:
       IF fooError THEN Exceptions.raise(exceptions, "FooError"); END;
 
      IF barError THEN Exceptions.raise(exceptions, "BarError"); END;
to:
       IF fooError THEN Exceptions.raise(exceptions, "FooError"); (* or here? *) END;
       IF barError THEN Exceptions.raise(exceptions, "BarError"); (* or here? *) END;
Added lines 68-70:

    (* or here? *)

2010-04-14 16:35 by benjk -
Changed line 38 from:
   (* control returns here if exceptions occurs while executing DoStuff *)
to:
   (* does control return here if exceptions occur while executing DoStuff? *)
2010-04-14 15:54 by benjk -
Changed line 22 from:
PROCEDURE HandleFooException;
to:
PROCEDURE CustomFooExceptionHandler;
Changed lines 25-27 from:
END HandleFooException;

PROCEDURE HandleBarException;
to:
END CustomFooExceptionHandler;

PROCEDURE CustomBarExceptionHandler;
Changed lines 30-31 from:
END HandleBarException;
to:
END CustomBarExceptionHandler;
Changed lines 33-35 from:
   Foobar.exceptions["FooError"] := HandleFooException;
    Foobar.exceptions["BarError"] := HandleBarException;
to:
   Foobar.exceptions["FooError"] := CustomFooExceptionHandler;
    Foobar.exceptions["BarError"] := CustomBarExceptionHandler;
Changed lines 74-75 from:
END HandleFooException;
to:
END DefaultFooExceptionHandler;
Changed line 79 from:
END HandleBarException;
to:
END DefaultBarExceptionHandler;
2010-04-14 15:53 by benjk -
Changed line 16 from:
The following example shows how to install exception handlers into an imported library module's exception dispatch table:
to:
The following example shows how to install custom exception handlers into an imported library module's exception dispatch table:
2010-04-14 15:52 by benjk -
Added lines 71-80:
PROCEDURE DefaultFooExceptionHandler;
BEGIN
    ...
END HandleFooException;

PROCEDURE DefaultBarExceptionHandler;
BEGIN
    ...
END HandleBarException;

Added lines 83-84:
   exceptions["FooError"] := DefaultFooExceptionHandler;
    exceptions["BarError"] := DefaultBarExceptionHandler;
2010-04-14 15:50 by benjk -
Changed line 54 from:
The following example shows how to create a dispatch table and raise exceptions:
to:
The following example shows how to create and initialise an exception dispatch table and how to raise exceptions:
2010-04-14 15:49 by benjk -
Changed line 42 from:
The following example shows how to export an exception dispatch table for use by client modules:
to:
The following example shows how to declare and export an exception dispatch table for use by client modules:
2010-04-14 15:48 by benjk -
Changed lines 16-17 from:
The following example shows how to create a dispatch table, install a handler and raise an exception:
to:
The following example shows how to install exception handlers into an imported library module's exception dispatch table:
Added lines 42-43:
The following example shows how to export an exception dispatch table for use by client modules:
Added lines 53-54:

The following example shows how to create a dispatch table and raise exceptions:
2010-04-14 15:45 by benjk -
Changed line 38 from:
   (* if exceptions occurs while executing DoStuff *)
to:
   (* control returns here if exceptions occurs while executing DoStuff *)
2010-04-14 15:44 by benjk -
Changed lines 20-23 from:
IMPORT Exceptions;

VAR exceptions : Exceptions
;
to:
IMPORT Foobar;
Added lines 27-31:
PROCEDURE HandleBarException;
BEGIN
    ...
END HandleBarException;

Changed lines 33-41 from:
   NEW(exceptions);
    exceptions
["FooError"] := HandleFooException;

    REPEAT
        dangerousOperation;
       IF ... THEN Exceptions.raise(exceptions, "FooError");
    UNTIL endCondition;

    DISPOSE(exceptions);
to:
   Foobar.exceptions["FooError"] := HandleFooException;
    Foobar.exceptions["BarError"] := HandleBarException;

    Foobar.DoStuff;

    (* if exceptions occurs while executing DoStuff *)
Added lines 41-69:

[@DEFINITION MODULE Foobar;

IMPORT Exceptions;

VAR exceptions : Exceptions;

PROCEDURE DoStuff;

END Foobar.@]

[@IMPLEMENTATION MODULE Foobar;

PROCEDURE DoStuff;
BEGIN
    REPEAT
        dangerousOperation;
        IF fooError THEN Exceptions.raise(exceptions, "FooError"); END;
        IF barError THEN Exceptions.raise(exceptions, "BarError"); END;
    UNTIL endCondition;

    doMoreStuff;
    doYetMoreStuff;
    RETURN;
END DoStuff;

BEGIN (* module initialisation *)
    NEW(exceptions);
END Foobar.@]
2010-04-14 13:26 by benjk -
Changed line 52 from:
TYPE Exception = ARRAY 20 OF CHAR;
to:
TYPE Exception = ARRAY 32 OF CHAR;
2010-04-14 13:18 by benjk -
Added lines 14-17:
!!!Example Code

The following example shows how to create a dispatch table, install a handler and raise an exception:

Changed lines 41-43 from:
to:
!!!Library Interface

The following shows an example library interface:
2010-04-14 12:58 by benjk -
Added line 7:
The following operations are required:
2010-04-14 12:57 by benjk -
Changed lines 3-4 from:
This article describes a lightweight exception handling system that is entirely library based and does not require any language support. It employs dispatch tables to store handlers for exceptions. In order to raise an exception, a dispatch table must first be created and a handler for the exception must be stored in the table.
to:
This article describes a lightweight exception handling system that is entirely library based and does not require any language support. It employs dispatch tables to store handlers for exceptions. In order to raise an exception, a dispatch table must first be created and a handler for the exception must be stored in the table.

!!!Required Operations

* create a dispatch table
* insert a new handler
* remove a handler
* raise an exception
* destroy a dispatch table
2010-04-14 12:46 by benjk -
Changed lines 3-4 from:
This article describes a lightweight exception handling system that is entirely library based and does not require any language support.
to:
This article describes a lightweight exception handling system that is entirely library based and does not require any language support. It employs dispatch tables to store handlers for exceptions. In order to raise an exception, a dispatch table must first be created and a handler for the exception must be stored in the table.
2010-04-14 12:36 by benjk -
Added lines 1-4:
!!!Synopsis

This article describes a lightweight exception handling system that is entirely library based and does not require any language support.

Added line 25:
   DISPOSE(exceptions);
Changed lines 61-67 from:
PROCEDURE [!] installHandler ( dispatchTable : Exceptions; e : Exception; handler : Handler );
(* Stores handler for exception e in dispatchTable, overwrites the previous handler if e is already present *)

PROCEDURE [-] removeHandler ( dispatchTable : Exceptions; e : Exception );
(* Removes the handler for exception e from dispatchTable *)

to:
PROCEDURE [!] pushHandler ( dispatchTable : Exceptions; e : Exception; handler : Handler );
(* Pushes a new handler onto the handler stack for exception e in dispatchTable *)

PROCEDURE [-] popHandler ( dispatchTable : Exceptions; e : Exception );
(* Removes the topmost handler from the handler stack for exception e in dispatchTable *)

Changed lines 70-73 from:
PROCEDURE [IN] exceptionDefined ( dispatchTable : Exceptions; e : Exception ) : BOOLEAN;
(* Returns TRUE if exception e is defined in dispatchTable, otherwise returns FALSE *)

to:
PROCEDURE [IN] handlerExists ( dispatchTable : Exceptions; e : Exception ) : BOOLEAN;
(* Returns TRUE if a handler exists for exception e in dispatchTable, otherwise returns FALSE *)

Changed line 77 from:
(* Raises exception e using dispatchTable *)
to:
(* Raises exception e by calling the topmost handler for e in dispatchTable *)
2010-04-14 11:53 by benjk -
Added lines 1-24:
[@MODULE UseExceptions;

IMPORT Exceptions;

VAR exceptions : Exceptions;

PROCEDURE HandleFooException;
BEGIN
    ...
END HandleFooException;

BEGIN (* Main *)
    NEW(exceptions);
    exceptions["FooError"] := HandleFooException;

    REPEAT
        dangerousOperation;
        IF ... THEN Exceptions.raise(exceptions, "FooError");
    UNTIL endCondition;

END UseExceptions.@]


2010-04-14 11:44 by benjk -
Added line 4:
2010-04-14 11:43 by benjk -
Added lines 42-47:


(* raise an exception *)

PROCEDURE raise ( dispatchTable : Exceptions; e : Exception );
(* Raises exception e using dispatchTable *)
2010-04-14 11:41 by benjk -
Changed lines 25-26 from:
(* Searches for exception in dispatch table, if found passes TRUE in found and returns its handler, otherwise passes FALSE *)
to:
(* Searches for exception e in dispatch table, if found passes TRUE in found and returns its handler,
 
otherwise passes FALSE *)
2010-04-14 11:41 by benjk -
Changed line 24 from:
PROCEDURE [.] handlerForException ( dispatchTable : Exceptions; exception : Exception; VAR found : BOOLEAN ) : Handler;
to:
PROCEDURE [.] handlerForException ( dispatchTable : Exceptions; e : Exception; VAR found : BOOLEAN ) : Handler;
Changed lines 30-36 from:
PROCEDURE [!] installHandler ( dispatchTable : Exceptions; exception : Exception; handler : Handler );
(* Stores handler for exception in dispatchTable, overwrites the previous handler if exception is already present *)

PROCEDURE [-] removeHandler ( dispatchTable : Exceptions; exception : Exception );
(* Removes the handler for exception from dispatchTable *)

to:
PROCEDURE [!] installHandler ( dispatchTable : Exceptions; e : Exception; handler : Handler );
(* Stores handler for exception e in dispatchTable, overwrites the previous handler if e is already present *)

PROCEDURE [-] removeHandler ( dispatchTable : Exceptions; e : Exception );
(* Removes the handler for exception e from dispatchTable *)

Changed lines 39-42 from:
PROCEDURE [IN] exceptionDefined ( dispatchTable : Exceptions; exception : Exception ) : BOOLEAN;
(* Returns TRUE if exception is defined in dispatchTable, otherwise returns FALSE *)

to:
PROCEDURE [IN] exceptionDefined ( dispatchTable : Exceptions; e : Exception ) : BOOLEAN;
(* Returns TRUE if exception e is defined in dispatchTable, otherwise returns FALSE *)

Changed lines 51-54 from:
PROCEDURE [FOR] nextException ( dispatchTable : Exceptions; VAR exception : Exception; VAR handler : Handler );
(* Finds the successor of exception and passes its exception/handler pair back in exception and handler.
  If the null key is passed in then the first exception/handler pair is passed back in exception and handler.
  If no successor is found then the null key is passed back in exception
and handler is undefined. *)
to:
PROCEDURE [FOR] nextException ( dispatchTable : Exceptions; VAR e : Exception; VAR handler : Handler );
(* Finds the successor of e and passes its exception/handler pair back in exception and handler.
  If the null key is passed in then the first exception/handler pair is passed back.
  If no successor is found then the null key is passed back in e
and handler is undefined. *)
2010-04-14 11:39 by benjk -
Added lines 1-62:
[@DEFINITION MODULE Exceptions;

(* Exception handling library *)

TYPE Exceptions = OPAQUE;

TYPE Exception = ARRAY 20 OF CHAR;

TYPE Handler = PROCEDURE;


(* null key *)

CONST [NIL] nullKey = 0C;


(* allocator *)

PROCEDURE [NEW] new ( VAR dispatchTable : Exceptions );


(* accessor *)

PROCEDURE [.] handlerForException ( dispatchTable : Exceptions; exception : Exception; VAR found : BOOLEAN ) : Handler;
(* Searches for exception in dispatch table, if found passes TRUE in found and returns its handler, otherwise passes FALSE *)


(* mutators *)

PROCEDURE [!] installHandler ( dispatchTable : Exceptions; exception : Exception; handler : Handler );
(* Stores handler for exception in dispatchTable, overwrites the previous handler if exception is already present *)

PROCEDURE [-] removeHandler ( dispatchTable : Exceptions; exception : Exception );
(* Removes the handler for exception from dispatchTable *)


(* membership test *)

PROCEDURE [IN] exceptionDefined ( dispatchTable : Exceptions; exception : Exception ) : BOOLEAN;
(* Returns TRUE if exception is defined in dispatchTable, otherwise returns FALSE *)


(* counter *)

PROCEDURE [COUNT] exceptionCount ( dispatchTable : Exceptions ) : LONGCARD;
(* Returns the number of exceptions defined in dispatchTable *)


(* iterator *)

PROCEDURE [FOR] nextException ( dispatchTable : Exceptions; VAR exception : Exception; VAR handler : Handler );
(* Finds the successor of exception and passes its exception/handler pair back in exception and handler.
  If the null key is passed in then the first exception/handler pair is passed back in exception and handler.
  If no successor is found then the null key is passed back in exception and handler is undefined. *)


(* destructor *)

PROCEDURE [DISPOSE] dispose ( VAR dispatchTable : Exceptions );
(* Deallocates dispatchTable and passes NIL back *)

END Exceptions.@]