-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathex8-exceptions.rkt
55 lines (48 loc) · 1.62 KB
/
ex8-exceptions.rkt
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
#lang racket
;; EXCEPTIONS ARE ALREADY IMPLEMENTED IN RACKET
;; but it's good to know how to do it ourselves
(define *handlers* '())
; *...* (called earmuffs) is a convention for mutable globals
;; utils
(define (push-handler proc)
(set! *handlers* (cons proc *handlers*)))
(define (pop-handler)
(let ([head (car *handlers*)])
(set! *handlers* (cdr *handlers*))
head))
(define (throw x)
(if (pair? *handlers*) ; = (not (empty? *handlers*))
((pop-handler) x) ; calling the return of 'pop-handler' on 'x'
(error (string-append "Error: too many throws. Received " (~a x) ))))
; example:
(push-handler displayln)
(throw 5) ; => 5
(throw 5) ; => error
(define-syntax try
(syntax-rules (catch)
[(_ expr ...
(catch exception-id exception-body ...))
(call/cc (λ (exit)
; install the handler
(push-handler (λ (x) ; 'x' is the arg of 'throw'
(if (equal? x exception-id)
(exit
(begin exception-body ...))
; else
(throw x))))
(let ([res (begin expr ...)])
(pop-handler)
res)))]))
(define (foo)
(displayln "Foo")
(throw "math-exception"))
(try
(displayln "Before foo")
(foo) ; throws bad-foo
(display "After foo") ; unreached code
(catch "math-exception"
; handle the exception here
(displayln "I caught a throw.")
#f)) ;=> #f
; ...
; if we try to catch an unregistered exception, we'll have an error: contract violation