File: Exception.Mod

package info (click to toggle)
oo2c64 1.5.0-1
  • links: PTS
  • area: main
  • in suites: potato
  • size: 8,904 kB
  • ctags: 5,775
  • sloc: ansic: 97,209; sh: 473; makefile: 344; perl: 57; lisp: 21
file content (202 lines) | stat: -rw-r--r-- 10,202 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
(* 	$Id: Exception.Mod,v 1.9 1999/10/03 11:46:22 ooc-devel Exp $	 *)
MODULE Exception [FOREIGN "C"; LINK FILE "Exception.c" END];
(*  Provides facilities to raise and handle exceptions.
    Copyright (C) 1997, 1998  Michael van Acken, Eric Nikitin

    This module is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public License
    as published by the Free Software Foundation; either version 2 of
    the License, or (at your option) any later version.

    This module is distributed in the hope that it will be useful, but
    WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with OOC. If not, write to the Free Software Foundation,
    59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*)
<* Warnings := FALSE *>


(* Exceptions are events that may require special processing by the user 
   program or by the implementation. 
   
   Exceptions may be raised by the computer's error-detection mechanisms,
   via calls to HALT or ASSERT, by the user program itself, or by actions
   external to the program.
   
   The primary use of this module is to provide error handling and allow
   programmer control over both system and language ( HALT and ASSERT )
   exception handling. The programmer may define handlers which can be
   used in place of those defined by the implementation.
*)

(*
Notes:
Wherever the word `thread' appears below it should be read as
`program' for the moment.  Multi-threading isn't supported yet. 

There are two states of program execution: normal and exceptional.
Until the first call to RAISE the program is in the normal execution
state.  After that it stays in the exceptional execution state until
ACKNOWLEDGE or RETRY is called.  

The restriction of PUSHCONTEXT that at most one context can be active
in a procedure allows an efficient implementation of the context stack
without falling back upon heap objects.

The state of all nonglobal variables that were modified after a
PUSHCONTEXT is undefined if the context is activated again by raising
an exception or calling RETRY.  The reason is simple: while the
compiler ensures that the evaluation of a piece of code delivers the
correct results in the end, it does not ensure that the state of an
interrupted computation is correctly reflected by the memory contents
at the time of the interruption.  An additional restriction affects
exceptions that weren't initiated by an explicit call to RAISE, i.e.,
failed run-time checks and external signals.  For these exceptions the
exact place of the raised execption, i.e., the set of instructions that
were completed before it was raised, is undefined.  The reason is that
a sequence of instructions as specified in the source code may be
evaluated in a different order or in an overlapped fashion in the
emitted machine code.  

Unlike Modula-2, the programmer is responsible for managing the stack of
exception handlers.  The stack is primarily manipulated through the procedures 
PUSHCONTEXT and POPCONTEXT.  The only other action that changes the stack is
a raised exception while the program is an exceptional execution state: this
will pop the topmost context (that was responsible for the exception) from the
stack before moving control to the then topmost execution context.  Raising an
exception in the state of normal execution will _not_ change the stack.  
Therefore every call to PUSHCONTEXT must have exactly one matching call to
POPCONTEXT in the same procedure, assuming that the program parts in between
are completed without raising an exception.

If a stack underflow occurs when POPCONTEXT is called, an exception is raised.
If an execution context is left of the stack that doesn't correspond to a valid
procedure, i.e. a procedure doing a PUSHCONTEXT was left without doing a 
matching POPCONTEXT, activating the context by raising an exception will 
transfer the program into a completely undefined state.  Most likely it'll 
abort due to a segmentation violation or a comparable error, or the stack of
execution contexts is rolled back until a valid context is reached.  There is
no way to check for such a situation.  Any programmer should be aware that an
invalid context stack can cause considerable grief.

With the procedure `SetException' of module Signal a signal handler can be 
installed that will raise an exception for a given signal number.  Unless 
specified otherwise, signals will trigger their respective default actions.
*)


CONST
  (* the following exception numbers belong to the source `runtime'; they 
     correspond to failed run-time checks; note for maintainer: this list has
     to be in sync with the one defined in __Exception.h *)
  derefOfNIL* = 1;       (* dereference of NIL or type test on NIL *)
  realDivByZero* = 2;    (* integer or real division by zero *)
  integerDivByZero* = 3; (* integer or real division by zero *)
  realOverflow* = 4;     (* real overflow (conversion or arithmetic op) *)
  integerOverflow* = 5;  (* integer overflow (conversion or arithmetic op) *)
  illegalLength* = 6;    (* NEW was called with negative length for array *)
  outOfMemory* = 7;      (* NEW couldn't allocate the requested memory *)
  indexOutOfRange* = 8;  (* array index out of range *)
  elementOutOfRange* = 9;(* set element out of range *)
  endOfFunction* = 10;   (* control reaches end of function procedure *)
  noMatchingLabel* = 11; (* no matching label in CASE construct *)
  noValidGuard* = 12;    (* all guards of WITH failed *)
  typeGuardFailed* = 13; (* type guard failed *)
  typeAssertFailed* = 14;(* illegal type of target of record assignment *)
  stackOverflow* = 15;   (* stack overflow *)
  
TYPE
  Number* = LONGINT;
  Source* = POINTER TO SourceDesc;
  SourceDesc* = RECORD
  END;

VAR
  (* these two exception variables are associated to the standard
     predefined procedures HALT and ASSERT; HALT(n) is equivalent to 
     RAISE(halt, n, ""), and ASSERT(FALSE, n) to RAISE (assert, n, "") *)
  halt-: Source;
  assert-: Source;
  (* this exception source is used to report failed run-time checks: *)
  runtime-: Source;

PROCEDURE [PROC_ID=1] PUSHCONTEXT* (VAR source: Source);
(* Pushes the current execution context onto the exception handler
stack and sets `source' to NIL.  If the context is reactivated later by 
raising an exception, it will be set to the exception's source.
Only one context can be pushed per procedure at a time.  During a 
single procedure evaluation two successive calls to PUSHCONTEXT without
a POPCONTEXT in between are not allowed and will result in undefined
program behaviour.
Note: All nonglobal variables of the enclosing procedures that were
modified after the initial call to PUSHCONTEXT are undefined when the
context is activated again by raising an exception.  *)

PROCEDURE POPCONTEXT*;
(* Removes the exception handler on the top of the stack.  During the
execution of a procedure the dynamic number of calls to POPCONTEXT has
to balance the ones to PUSHCONTEXT.  If the stack is empty an exception
is raised.  If the program is in an exceptional execution state at the
point where POPCONTEXT is called, the exception is raised again, thereby
passing it along to the next higher exception handler.  *)

PROCEDURE RETRY*;
(* If the current thread is in the exceptional execution state, the
context on top of the stack of exception handlers is reactivated in
the state of normal execution; this will look as if the corresponding
call of PUSHCONTEXT will return again, with the parameter `source' set 
to NIL.  This allows the "normal" part to be re-executed.  Be very
careful when using this since all local variables of the enclosing
procedure that were modified after the initial call to PUSHCONTEXT are
undefined when activating the context again. 
If the current thread is in the normal execution state, calling
RETRY will raise an exception.  *)

PROCEDURE ACKNOWLEDGE*;
(* If the current thread is in the exceptional execution state, it
is placed back into the state of normal execution.  Otherwise an
exception will be raised.  Calling this procedure indicates that an
exception has been handled without retrying the "normal" part.  *)

PROCEDURE AllocateSource* (VAR newSource: Source);
(* Allocates a unique value of type Source.  If an unique
value cannot be allocated, an exception will be raised.  *)

PROCEDURE RAISE* (source: Source; number: Number;
                  message: ARRAY OF CHAR);
(* Associates the given values of source, number and message with the
current context and raises an exception.  This means that the current
thread switches into the exceptional execution state and activates
a program context from the stack of exception handlers. If the program
is in the normal execution state, the context on top of the stack is
selected.  If it's in an exceptional execution state the stack is 
popped first.  Reactivating the execution context will look as if the 
corresponding call to PUSHCONTEXT will return a second time, this time 
returning the first argument of RAISE in the variable parameter `source'.

The message should have the format "[<module>] <description>".  It may be 
truncated by RAISE to an implementation-defined length.   Using a value of NIL 
for the first argument will raise an exception. *)


PROCEDURE CurrentNumber* (source: Source): Number; 
(* If the current thread is in the exceptional execution state
because of the raising of an exception from source, returns the
corresponding number, and otherwise raises an exception.  *)

PROCEDURE GetMessage* (VAR text: ARRAY OF CHAR);
(* If the current thread is in the exceptional execution state,
returns the possibly truncated string associated with the current
context.  Otherwise, in normal execution state, returns the empty
string.  *)

PROCEDURE IsExceptionalExecution* (): BOOLEAN;
(* If the current thread is in the exceptional execution state
because of the raising of an exception, returns TRUE, and otherwise
returns FALSE.  *)

END Exception.