-
Notifications
You must be signed in to change notification settings - Fork 0
/
Module (chicken condition)
452 lines (317 loc) · 14.2 KB
/
Module (chicken condition)
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
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
[[tags: manual]]
[[toc:]]
== Module (chicken condition)
This module provides various procedures and special forms for raising
and handling exceptions with "condition objects". Condition objects
provide a structured and composable way to encode the kind of
exception that took place, and provide the necessary context.
CHICKEN's exception handling is based on the
[[http://srfi.schemers.org/srfi-12/srfi-12.html|SRFI-12]] exception
system. This document contains the core of the SRFI-12 spec as well
as CHICKEN implementation specifics.
There is also a {{srfi-12}} or {{(srfi 12)}} module which only
includes the standard procedures and macros from the SRFI document,
without the CHICKEN extensions. {{(chicken condition)}} offers the
complete set of procedures and macros, both CHICKEN-specific and
standard SRFI-12.
== CHICKEN implementation
=== System conditions
All error-conditions signaled by the system are of kind {{exn}}.
The following composite conditions are additionally defined:
<table>
<tr><td> (exn arity) </td><td>
Signaled when a procedure is called with the wrong number of arguments.
</td></tr><tr><td> (exn type) </td><td>
Signaled on type-mismatch errors, for example when an argument of the wrong
type is passed to a built-in procedure.
</td></tr><tr><td> (exn arithmetic) </td><td>
Signaled on arithmetic errors, like division by zero.
</td></tr><tr><td> (exn i/o) </td><td>
Signaled on input/output errors.
</td></tr><tr><td> (exn i/o file) </td><td>
Signaled on file-related errors.
</td></tr><tr><td> (exn i/o net) </td><td>
Signaled on network errors.
</td></tr><tr><td> (exn bounds) </td><td>
Signaled on errors caused by accessing non-existent elements of a collection.
</td></tr><tr><td> (exn runtime) </td><td>
Signaled on low-level runtime-system error-situations.
</td></tr><tr><td> (exn runtime limit) </td><td>
Signaled when an internal limit is exceeded (like running out of memory).
</td></tr><tr><td> (exn match) </td><td>
Signaled on errors raised by failed matches (see the section on {{match}}).
</td></tr><tr><td> (exn syntax) </td><td>
Signaled on syntax errors.
</td></tr>
</table>
=== Notes
* All error-exceptions (of the kind {{exn}}) are non-continuable.
* Error-exceptions of the {{exn}} kind have additional {{arguments}} and
{{location}} properties that contain the arguments passed to the
exception-handler and the name of the procedure where the error occurred (if
available).
* Within the interpreter (csi), a user-interrupt ({{signal/int}}) signals an
exception of the kind {{user-interrupt}}.
* The procedure {{condition-property-accessor}} accepts an optional third
argument. If the condition does not have a value for the desired property and
if the optional argument is given, no error is signaled and the accessor
returns the third argument.
* On platforms that support the {{sigprocmask(3)}} POSIX API function,
the signals {{SIGSEGV}}, {{SIGFPE}}, {{SIGBUS}} and {{SIGILL}} will be
caught and trigger an exception instead of aborting the process, if
possible. If the unwinding and handling of the signal raises one of
these signals once again, the process will abort with an error
message.
=== Additional API
==== condition-case
<macro>(condition-case EXPRESSION CLAUSE ...)</macro>
Evaluates {{EXPRESSION}} and handles any exceptions that are covered by
{{CLAUSE ...}}, where {{CLAUSE}} should be of the following form:
CLAUSE = ([VARIABLE] (KIND ...) BODY ...)
If provided, {{VARIABLE}} will be bound to the signaled exception
object. {{BODY ...}} is executed when the exception is a property-
or composite condition with the kinds given {{KIND ...}} (unevaluated).
If no clause applies, the exception is re-signaled in the same dynamic
context as the {{condition-case}} form.
<enscript highlight=scheme>
(define (check thunk)
(condition-case (thunk)
[(exn file) (print "file error")]
[(exn) (print "other error")]
[var () (print "something else")] ) )
(check (lambda () (open-input-file ""))) ; -> "file error"
(check (lambda () some-unbound-variable)) ; -> "othererror"
(check (lambda () (signal 99))) ; -> "something else"
(condition-case some-unbound-variable
((exn file) (print "ignored")) ) ; -> signals error
</enscript>
==== get-condition-property
<procedure>(get-condition-property CONDITION KIND PROPERTY [DEFAULT])</procedure>
A slightly more convenient condition property accessor, equivalent to
((condition-property-accessor KIND PROPERTY [DEFAULT]) CONDITION)
==== condition
<procedure>(condition LST1 LST2 ...)</procedure>
This is a more convenient constructor for conditions. Each of
{{LST1}}, {{LST2}} etc is a list of the following form:
(KIND PROPERTY1 VALUE1 PROPERTY2 VALUE2 ...)
In other words, the following:
(signal (condition '(exn location foo message "hi") '(file bar 1)))
is equivalent to the SRFI-12 code:
(signal (make-composite-condition
(make-property-condition 'exn 'location 'foo 'message "hi")
(make-property-condition 'file 'bar 2)))
==== condition->list
<procedure>(condition->list CONDITION)</procedure>
This procedure converts a condition object into a list holding all the
conditions that are represented by the ''CONDITION'' object. It is
formatted as follows:
((KIND1 PROPERTY1 VALUE1 PROPERTY2 VALUE2 ...) (KIND2 ... ) ... )
There is no guaranteed order within the list.
==== print-error-message
<procedure>(print-error-message EXN [PORT [HEADER]])</procedure>
Prints an appropriate error message to {{PORT}} (which defaults to the
value of {{(current-output-port)}} for the object {{EXN}}. {{EXN}} may
be a condition, a string or any other object. The output is prefixed
by the {{HEADER}}, which defaults to {{"Error:"}}.
== SRFI-12 specification
A Scheme implementation ("the system") raises an exception whenever an
error is to be signaled or whenever the system determines that evaluation
cannot proceed in a manner consistent with the semantics of Scheme. A
program may also explicitly raise an exception.
Whenever the system raises an exception, it invokes the current exception
handler with a condition object (encapsulating information about the
exception) as its only argument. Any procedure accepting one argument
may serve as an exception handler. When a program explicitly raises an
exception, it may supply any object to the exception handler.
An exception is either continuable or non-continuable. When the current
exception handler is invoked for a continuable exception, the continuation
uses the handler's result(s) in an exception-specific way to continue.
When an exception handler is invoked for a non-continuable exception,
the continuation raises a non-continuable exception indicating that the
exception handler returned. On CHICKEN, system error exceptions
(of kind {{exn}}) are non-continuable.
=== Exception Handlers
==== current-exception-handler
<parameter>(current-exception-handler [PROCEDURE])</parameter><br>
Sets or returns the current exception handler, a procedure of one
argument, the exception object.
==== with-exception-handler
<procedure>(with-exception-handler handler thunk)</procedure><br>
Returns the result(s) of invoking ''thunk''. The ''handler'' procedure
is installed as the current exception handler in the dynamic context of
invoking ''thunk''.
Example:
<enscript highlight=scheme>
(call-with-current-continuation
(lambda (k)
(with-exception-handler (lambda (x) (k '()))
(lambda () (car '())))))
;=> '()
</enscript>
Note that the handler procedure must somehow return non-locally out of
the dynamic extent of the {{with-exception-handler}} form, because
returning normally will signal yet another exception and thus result
in non-termination.
==== handle-exceptions
<macro>(handle-exceptions var handle-expr expr1 expr2 ...)</macro><br>
Evaluates the body expressions ''expr1'', ''expr2'', ... in sequence with
an exception handler constructed from ''var'' and ''handle-expr''. Assuming
no exception is raised, the result(s) of the last body expression is(are)
the result(s) of the {{handle-exceptions}} expression.
The exception handler created by {{handle-exceptions}} restores the dynamic
context (continuation, exception handler, etc.) of the {{handle-exceptions}}
expression, and then evaluates ''handle-expr'' with ''var'' bound to the
value provided to the handler.
Examples:
<enscript highlight=scheme>
(handle-exceptions exn
(begin
(display "Went wrong")
(newline))
(car '()))
; displays "Went wrong"
(handle-exceptions exn
(cond
((eq? exn 'one) 1)
(else (abort exn)))
(case (random 3)
[(0) 'zero]
[(1) (abort 'one)]
[else (abort "Something else")]))
;=> 'zero, 1, or (abort "Something else")
</enscript>
=== Raising Exceptions
==== abort
<procedure>(abort obj)</procedure><br>
Raises a non-continuable exception represented by ''obj''. The {{abort}}
procedure can be implemented as follows:
<enscript highlight=scheme>
(define (abort obj)
((current-exception-handler) obj)
(abort (make-property-condition
'exn
'message
"Exception handler returned")))
</enscript>
The {{abort}} procedure does not ensure that its argument is a condition.
If its argument is a condition, {{abort}} does not ensure that the condition
indicates a non-continuable exception.
==== signal
<procedure>(signal obj)</procedure><br>
Raises a continuable exception represented by ''obj''. The {{signal}} procedure
can be implemented as follows:
<enscript highlight=scheme>
(define (signal exn)
((current-exception-handler) exn))
</enscript>
The {{signal}} procedure does not ensure that its argument is a condition.
If its argument is a condition, {{signal}} does not ensure that the condition
indicates a continuable exception.
=== Condition Objects
==== condition?
<procedure>(condition? obj)</procedure><br>
Returns #t if ''obj'' is a condition, otherwise returns #f. If any of
the predicates listed in Section 3.2 of the R5RS is true of ''obj'', then
{{condition?}} is false of ''obj''.
Rationale: Any Scheme object may be passed to an exception handler. This
would cause ambiguity if conditions were not disjoint from all of Scheme's
standard types.
==== make-property-condition
<procedure>(make-property-condition kind-key prop-key value ...)</procedure><br>
This procedure accepts any even number of arguments after ''kind-key'',
which are regarded as a sequence of alternating ''prop-key'' and ''value''
objects. Each ''prop-key'' is regarded as the name of a property, and
each ''value'' is regarded as the value associated with the ''key'' that
precedes it. Returns a ''kind-key'' condition that associates the given
''prop-key''s with the given ''value''s.
==== make-composite-condition
<procedure>(make-composite-condition condition ...)</procedure><br>
Returns a newly-allocated condition whose components correspond to the the
given ''condition''s. A predicate created by {{condition-predicate}} returns
true for the new condition if and only if it returns true for one or more
of its component conditions.
==== condition-predicate
<procedure>(condition-predicate kind-key)</procedure><br>
Returns a predicate that can be called with any object as its argument.
Given a condition that was created by {{make-property-condition}}, the
predicate returns #t if and only if ''kind-key'' is EQV? to the kind key
that was passed to {{make-property-condition}}. Given a composite condition
created with {{make-composite-condition}}, the predicate returns #t if and only
if the predicate returns #t for at least one of its components.
==== condition-property-accessor
<procedure>(condition-property-accessor kind-key prop-key [default])</procedure><br>
Returns a procedure that can be called with any condition that satisfies
{{(condition-predicate ''kind-key'')}}. Given a condition that was created
by {{make-property-condition}} and ''kind-key'', the procedure returns the
value that is associated with ''prop-key''. Given a composite condition
created with {{make-composite-condition}}, the procedure returns the value that
is associated with ''prop-key'' in one of the components that satisfies
{{(condition-predicate ''kind-key'')}}.
On CHICKEN, this procedure accepts an optional third argument
DEFAULT. If the condition does not have a value for the desired
property and if the optional argument is given, no error is signaled
and the accessor returns the third argument.
When the system raises an exception, the condition it passes to the
exception handler includes the {{'exn}} kind with the following
properties:
; message : the error message
; arguments: the arguments passed to the exception handler
; location: the name of the procedure where the error occurred (if available)
Thus, if ''exn'' is a condition representing a system exception,
then
<enscript highlight=scheme>
((condition-property-accessor 'exn 'message) exn)
</enscript>
extracts the error message from ''exn''. Example:
<enscript highlight=scheme>
(handle-exceptions exn
(begin
(display "Went wrong: ")
(display
((condition-property-accessor 'exn 'message) exn))
(newline))
(car '()))
; displays something like "Went wrong: can't take car of nil"
</enscript>
=== More Examples
<enscript highlight=scheme>
(define (try-car v)
(let ((orig (current-exception-handler)))
(with-exception-handler
(lambda (exn)
(orig (make-composite-condition
(make-property-condition
'not-a-pair
'value
v)
exn)))
(lambda () (car v)))))
(try-car '(1))
;=> 1
(handle-exceptions exn
(if ((condition-predicate 'not-a-pair) exn)
(begin
(display "Not a pair: ")
(display
((condition-property-accessor 'not-a-pair 'value) exn))
(newline))
(abort exn))
(try-car 0))
; displays "Not a pair: 0"
(let* ((cs-key (list 'color-scheme))
(bg-key (list 'background))
(color-scheme? (condition-predicate cs-key))
(color-scheme-background
(condition-property-accessor cs-key bg-key))
(condition1 (make-property-condition cs-key bg-key 'green))
(condition2 (make-property-condition cs-key bg-key 'blue))
(condition3 (make-composite-condition condition1 condition2)))
(and (color-scheme? condition1)
(color-scheme? condition2)
(color-scheme? condition3)
(color-scheme-background condition3)))
; => 'green or 'blue
</enscript>
----
Previous: [[Module (chicken blob)]]
Next: [[Module (chicken continuation)]]