This repository was archived by the owner on May 26, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathbinds.lisp
173 lines (152 loc) · 5.84 KB
/
binds.lisp
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
(in-package #:sandalphon.lambda-list)
;;;; BINDS
(defun generate-let* (llist body &rest forms)
(multiple-value-bind (binds decls)
(apply #'generate-bindings llist forms)
`(let* ,binds ,@decls ,@body)))
;; This here is the most basic binding-generation function that
;; the others are defined in terms of.
(defun generate-bindings (llist &rest forms)
(loop with safe = (if (lambda-list-safe llist)
(gensym "SAFETY")
nil)
with binds = (if safe
`((,safe ,(length-check llist (first forms))))
nil)
with declares = (if safe `((ignore ,safe)) nil)
for clause in (lambda-list-clauses llist)
do (multiple-value-bind (new-binds new-forms new-declares)
(clause-binds clause forms)
(setf binds (append binds new-binds)
forms new-forms
declares (append declares new-declares)))
finally (return (values binds declares))))
;;; Internal interface
;; return (values binds new-forms declares)
(defgeneric clause-binds (clause forms))
(defgeneric multiple-clause-binds (clause spec forms))
(defmethod clause-binds ((clause whole-clause) forms)
;; also handles macro CDR/cmf CDR-FUNCALL-THINGIE.
;; you know. the rest of the lambda list handling some other thing.
(let ((mapped (gensym "MAPPED")))
(values (append (when (clause-spec clause)
`((,(clause-spec clause) ,(first forms))))
`((,mapped (,(whole-map clause) ,(first forms)))))
(cons mapped (rest forms))
`((ignorable ,mapped)))))
(defmethod clause-binds ((clause environment-clause) forms)
(values `((,(clause-spec clause) ,(second forms))) forms nil))
(defmethod clause-binds ((clause multiple-clause) forms)
(loop with binds = nil
with declares = nil
for spec in (multiple-clause-specs clause)
do (multiple-value-bind (new-binds new-forms new-declares)
(multiple-clause-binds clause spec forms)
(setf binds (append binds new-binds)
forms new-forms
declares (append declares new-declares)))
finally (return (values binds forms declares))))
(defmethod clause-binds ((clause key-clause) forms)
(let ((keys (gensym "KEYS"))
(safety (if (clause-safe clause) (gensym "VERIFY") nil)))
;; c-n-m does multiple-clause
(multiple-value-bind (binds nforms decls)
(call-next-method clause (cons keys (rest forms)))
(values
(append `((,keys ,(first forms)))
(if safety
`((,safety (verify-keys
,keys
',(mapcar #'caar
(multiple-clause-specs clause))
',(key-clause-aok-p clause))))
nil)
binds)
nforms
(append (if safety `((ignore ,safety)) nil) decls)))))
(defun regular-binds (name form)
`((,name (car ,form))))
(defmethod multiple-clause-binds ((clause regular-clause) spec forms)
(values (regular-binds spec (first forms))
(cons (list 'cdr (first forms)) (rest forms))
nil))
(defmethod multiple-clause-binds ((clause specialized-regular-clause)
spec forms)
(values (regular-binds (first spec) (first forms))
(cons (list 'cdr (first forms)) (rest forms))
`((type ,(second spec) ,(first spec)))))
(defmethod multiple-clause-binds ((clause destructuring-regular-clause)
spec forms)
(if (symbolp spec)
(values (regular-binds spec (first forms))
(cons (list 'cdr (first forms)) (rest forms))
nil)
(let ((sym (gensym "DESTRUCTURE")))
(multiple-value-bind (r-binds r-decls)
(apply #'generate-bindings spec sym (rest forms))
(values
(append (regular-binds sym (first forms)) r-binds)
(cons (list 'cdr (first forms)) (rest forms))
r-decls)))))
(defun optional-binds (var -p default form)
`((,-p (if (null ,form) nil ,form))
(,var (if ,-p (car ,-p) ,default))))
(defmethod multiple-clause-binds ((clause optional-clause) spec forms)
(values
(optional-binds (first spec) (or (third spec) (gensym "PROVIDED-P"))
(second spec) (first forms))
(cons (list 'cdr (first forms)) (rest forms))
nil))
(defmethod multiple-clause-binds ((clause destructuring-optional-clause)
spec forms)
(destructuring-bind (var default -p) spec
(if (symbolp var)
(values (optional-binds var (or -p (gensym "PROVIDED-P"))
default (first forms))
(cons (list 'cdr (first forms)) (rest forms))
nil)
(let ((sym (gensym "DESTRUCTURE")))
(multiple-value-bind (r-binds r-decls)
(apply #'generate-bindings var sym (rest forms))
(values
(append (optional-binds sym (or -p (gensym "PROVIDED-P"))
default (first forms))
r-binds)
(cons (list 'cdr (first forms)) (rest forms))
r-decls))))))
(defmethod clause-binds ((clause rest-clause) forms)
(if (clause-spec clause)
(values `((,(clause-spec clause) ,(first forms)))
(list (clause-spec clause) (rest forms))
nil)
(values nil forms nil)))
(defun key-binds (key var -p default form)
(let ((not-found-tag (gensym))) ; gross
`((,-p (getf ,form ',key ',not-found-tag))
(,var (if (eq ,-p ',not-found-tag)
,default
,-p)))))
(defmethod multiple-clause-binds ((clause key-clause) spec forms)
(destructuring-bind ((key var) default -p) spec
(values (key-binds key var (or -p (gensym "PROVIDED-P"))
default (first forms))
forms
nil)))
(defmethod multiple-clause-binds ((clause destructuring-key-clause)
spec forms)
(destructuring-bind ((key var) default -p) spec
(let ((-p (or -p (gensym "PROVIDED-P"))))
(if (symbolp var)
(values (key-binds key var -p default (first forms))
(cons (list 'cdr (first forms)) (rest forms))
nil)
(let ((sym (gensym "DESTRUCTURE")))
(multiple-value-bind (r-binds r-decls)
(apply #'generate-bindings var sym (rest forms))
(values
(append (key-binds key sym -p default (first forms))
r-binds)
(cons (list 'cdr (first forms)) (rest forms))
r-decls)))))))
(defmethod multiple-clause-binds ((clause aux-clause) spec forms)
(values (list spec) forms nil))