-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmatch-defmacro.scm
96 lines (95 loc) · 3.44 KB
/
match-defmacro.scm
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
(define (match-expression? e) (and (pair? e) (eq? (car e) 'match)))
(define (match-input-expr e) (cadr e))
(define (match-clauses e) (cddr e))
(define (first-clause cs) (car cs))
(define (guard-clause? c)
(and (pair? (cadr c)) (eq? (car (cadr c)) 'guard)))
(define (guard-clause-expr c)
(if (guard-clause? c)
(cadadr c)
#t))
(define (rest-clause cs) (cdr cs))
(define (clause-pattern c) (car c))
(define (clause-expr c)
(if (guard-clause? c)
(cddr c)
(cdr c)))
(define (unquoted-empty? e)
(and (pair? e) (eq? (car e) 'unquote) (equal? (cdr e) '(()))))
(define (empty-pat? e) (or (unquoted-empty? e) (eq? e ',_)))
(define (var-pat? e)
(and (pair? e) (eq? (car e) 'unquote) (symbol? (cadr e))))
(define (var-pat e) (cadr e))
(define (empty-list-pat? e)
(and (pair? e) (eq? (car e) 'quote) (null? (cadr e))))
(define (datum-pattern? pattern)
(or (null? pattern) (symbol? pattern) (not (pair? pattern))))
(define (datum-pattern pattern)
(if (or (null? pattern) (symbol? pattern))
(list 'quote pattern)
pattern))
(define (compile-match p)
(let ((evaluated (gensym)))
`(let ([,evaluated ,(match-input-expr p)])
,(compile-clauses evaluated (match-clauses p)))))
(define (compile-clauses value clauses)
(if (null? clauses)
`'(error 'no-matching-pattern ,value)
(compile-clause
(list (list (clause-pattern (first-clause clauses)) value))
'(and)
'()
(clause-expr (first-clause clauses))
(compile-clauses value (rest-clause clauses))
(guard-clause-expr (first-clause clauses)))))
(define (compile-clause pat-val-pairs condition bindings conseq alter guard-pred)
(cond
[(null? pat-val-pairs)
(if (eq? guard-pred #t)
`(if ,condition (let ,bindings . ,conseq) ,alter)
(let ((alter-f (gensym)))
`(let ((,alter-f (lambda () ,alter)))
(if ,condition
(let ,bindings
(if ,guard-pred
(begin . ,conseq)
(,alter-f)))
(,alter-f))))
)]
[(empty-pat? (caar pat-val-pairs))
(compile-clause (cdr pat-val-pairs)
condition
bindings
conseq
alter
guard-pred)]
[(var-pat? (caar pat-val-pairs))
(compile-clause (cdr pat-val-pairs)
condition
(cons (list (var-pat (caar pat-val-pairs)) (cadar pat-val-pairs)) bindings)
conseq
alter
guard-pred)]
[(datum-pattern? (caar pat-val-pairs))
(compile-clause (cdr pat-val-pairs)
(append condition
`((equal? ,(datum-pattern (caar pat-val-pairs)) ,(cadar pat-val-pairs))))
bindings
conseq
alter
guard-pred)]
[(pair? (caar pat-val-pairs))
(let*
([first (car pat-val-pairs)]
[rest (cdr pat-val-pairs)]
[pat (car first)]
[val (cadr first)]
[left (list (car pat) (list 'car val))]
[right (list (cdr pat) (list 'cdr val))])
(compile-clause (append (list left right) rest)
(append condition `((pair? ,val)))
bindings
conseq
alter
guard-pred))]
[else (error compile-clause '())]))