This repository has been archived by the owner on Dec 5, 2022. It is now read-only.
-
-
Notifications
You must be signed in to change notification settings - Fork 9
/
condd.rkt
120 lines (102 loc) · 2.27 KB
/
condd.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
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
#lang racket/base
(require (for-syntax racket/base
syntax/parse))
(module+ test
(require rackunit/chk))
(define-syntax (condd stx)
(syntax-parse stx
#:literals (define else)
[(_)
#'(error 'condd "Missing else case")]
[(_ [else . d])
#'(let () . d)]
[(_ (define . d) ...+ . more)
#'(let ()
(define . d) ...
(condd . more))]
[(_ [test . b] . more)
#'(if test
(let () . b)
(condd . more))]))
(module+ test
(chk
(condd
[else (void)])
(void)
(condd
[else 1])
1
(condd
(define first 1)
[else (void)])
(void)
(condd
[#t 1])
1
(condd
(define first 1)
[(= first 2)
"2\n"]
(define first 2)
[(= first 2)
"2 again\n"]
[else
"Nope\n"])
"2 again\n"
#:exn
(condd
[#f 1]
[#f 2])
"Missing else"))
(begin-for-syntax
(define-splicing-syntax-class switch-clause
#:attributes (code-gen)
(pattern (~seq #:cond [t:expr e:expr ...+])
#:attr code-gen
(λ (k)
(quasisyntax/loc #'t
(if t (let () e ...) #,k))))))
(define-syntax (switch stx)
(syntax-parse stx
[(_)
(quasisyntax/loc stx
(error 'switch "Fell through without else clause"))]
[(_ #:else e:expr ...+)
(syntax/loc stx
(begin e ...))]
[(_ (~and x (~not y:keyword)) ...
sc:switch-clause . tail)
(quasisyntax/loc stx
(let ()
x ...
#,((attribute sc.code-gen)
(syntax/loc stx
(switch . tail)))))]))
(module+ test
(chk #:exn (switch)
"Fell through"
(switch #:else 1)
1
(switch #:else 1 2)
2
(switch #:cond [1 2])
2
(switch #:cond [#f 1] #:else 2)
2
(switch #:cond [1 (define x 2) x])
2
(switch #:cond [#f 1] #:cond [2 3] #:else 4)
3
(switch (define one 1)
#:cond [#f 1]
(define two 2)
#:cond [two (+ one one one)]
#:else 4)
3
(switch (define-syntax-rule (one) 1)
#:cond [#f 1]
(define two 2)
(set! two 3)
#:cond [two (+ (one) two)]
#:else 4)
4))