55121c9117727a0b2e64083b357e6bdd7f60d2d0
[sbcl.git] / src / code / parse-defmacro.lisp
1 ;;;; the PARSE-DEFMACRO function and related code
2
3 ;;;; This software is part of the SBCL system. See the README file for
4 ;;;; more information.
5 ;;;;
6 ;;;; This software is derived from the CMU CL system, which was
7 ;;;; written at Carnegie Mellon University and released into the
8 ;;;; public domain. The software is in the public domain and is
9 ;;;; provided with absolutely no warranty. See the COPYING and CREDITS
10 ;;;; files for more information.
11
12 (in-package "SB!KERNEL")
13
14 ;;; variables for accumulating the results of parsing a DEFMACRO. (Declarations
15 ;;; in DEFMACRO are the reason this isn't as easy as it sounds.)
16 (defvar *arg-tests* nil) ; tests that do argument counting at expansion time
17 (declaim (type list *arg-tests*))
18 (defvar *system-lets* nil) ; LET bindings done to allow lambda-list parsing
19 (declaim (type list *system-lets*))
20 (defvar *user-lets* nil) ; LET bindings that the user has explicitly supplied
21 (declaim (type list *user-lets*))
22 (defvar *env-var* nil) ; &ENVIRONMENT variable name
23
24 ;; the default default for unsupplied &OPTIONAL and &KEY args
25 (defvar *default-default* nil)
26
27 ;;; temps that we introduce and might not reference
28 (defvar *ignorable-vars*)
29 (declaim (type list *ignorable-vars*))
30
31 ;;; Return, as multiple values, a body, possibly a declare form to put
32 ;;; where this code is inserted, the documentation for the parsed
33 ;;; body, and bounds on the number of arguments.
34 (defun parse-defmacro (lambda-list arg-list-name body name error-kind
35                                    &key
36                                    (anonymousp nil)
37                                    (doc-string-allowed t)
38                                    ((:environment env-arg-name))
39                                    ((:default-default *default-default*))
40                                    (error-fun 'error)
41                                    (wrap-block t))
42   (multiple-value-bind (forms declarations documentation)
43       (parse-body body doc-string-allowed)
44     (let ((*arg-tests* ())
45           (*user-lets* ())
46           (*system-lets* ())
47           (*ignorable-vars* ())
48           (*env-var* nil))
49       (multiple-value-bind (env-arg-used minimum maximum)
50           (parse-defmacro-lambda-list lambda-list arg-list-name name
51                                       error-kind error-fun (not anonymousp)
52                                       nil)
53         (values `(let* (,@(when env-arg-used
54                             `((,*env-var* ,env-arg-name)))
55                         ,@(nreverse *system-lets*))
56                    ,@(when *ignorable-vars*
57                        `((declare (ignorable ,@*ignorable-vars*))))
58                    ,@*arg-tests*
59                    (let* ,(nreverse *user-lets*)
60                      ,@declarations
61                      ,@(if wrap-block
62                            `((block ,(fun-name-block-name name)
63                                ,@forms))
64                            forms)))
65                 `(,@(when (and env-arg-name (not env-arg-used))
66                       `((declare (ignore ,env-arg-name)))))
67                 documentation
68                 minimum
69                 maximum)))))
70
71 ;;; partial reverse-engineered documentation:
72 ;;;   TOPLEVEL is true for calls through PARSE-DEFMACRO from DEFSETF and
73 ;;;     DESTRUCTURING-BIND, false otherwise.
74 ;;; -- WHN 19990620
75 (defun parse-defmacro-lambda-list (possibly-dotted-lambda-list
76                                    arg-list-name
77                                    name
78                                    error-kind
79                                    error-fun
80                                    &optional
81                                    toplevel
82                                    env-illegal)
83   (let* (;; PATH is a sort of pointer into the part of the lambda list we're
84          ;; considering at this point in the code. PATH-0 is the root of the
85          ;; lambda list, which is the initial value of PATH.
86          (path-0 (if toplevel
87                      `(cdr ,arg-list-name)
88                      arg-list-name))
89          (path path-0) ; (will change below)
90          (now-processing :required)
91          (maximum 0)
92          (minimum 0)
93          (keys ())
94          (key-seen nil)
95          ;; ANSI specifies that dotted lists are "treated exactly as if the
96          ;; parameter name that ends the list had appeared preceded by &rest."
97          ;; We force this behavior by transforming dotted lists into ordinary
98          ;; lists with explicit &REST elements.
99          (lambda-list (do ((in-pdll possibly-dotted-lambda-list (cdr in-pdll))
100                            (reversed-result nil))
101                           ((atom in-pdll)
102                            (nreverse (if in-pdll
103                                          (list* in-pdll '&rest reversed-result)
104                                          reversed-result)))
105                         (push (car in-pdll) reversed-result)))
106          rest-name restp allow-other-keys-p env-arg-used)
107     (when (member '&whole (rest lambda-list))
108       (error "&WHOLE may only appear first in ~S lambda-list." error-kind))
109     (do ((rest-of-args lambda-list (cdr rest-of-args)))
110         ((null rest-of-args))
111       (macrolet ((process-sublist (var sublist-name path)
112                    (once-only ((var var))
113                      `(if (listp ,var)
114                           (let ((sub-list-name (gensym ,sublist-name)))
115                             (push-sub-list-binding sub-list-name ,path ,var
116                                                    name error-kind error-fun)
117                             (parse-defmacro-lambda-list ,var sub-list-name name
118                                                         error-kind error-fun))
119                           (push-let-binding ,var ,path nil)))))
120         (let ((var (car rest-of-args)))
121           (typecase var
122             (list
123              (case now-processing
124                ((:required)
125                 (when restp
126                   (defmacro-error "required argument after &REST/&BODY"
127                       error-kind name))
128                 (process-sublist var "SUBLIST-" `(car ,path))
129                 (setq path `(cdr ,path)
130                       minimum (1+ minimum)
131                       maximum (1+ maximum)))
132                ((:optionals)
133                 (destructuring-bind (varname &optional initform supplied-p)
134                     var
135                   (push-optional-binding varname initform supplied-p
136                                          `(not (null ,path)) `(car ,path)
137                                          name error-kind error-fun))
138                 (setq path `(cdr ,path)
139                       maximum (1+ maximum)))
140                ((:keywords)
141                 (let* ((keyword-given (consp (car var)))
142                        (variable (if keyword-given
143                                      (cadar var)
144                                      (car var)))
145                        (keyword (if keyword-given
146                                     (caar var)
147                                     (keywordicate variable)))
148                        (supplied-p (caddr var)))
149                   (push-optional-binding variable (cadr var) supplied-p
150                                          `(keyword-supplied-p ',keyword
151                                                               ,rest-name)
152                                          `(lookup-keyword ',keyword
153                                                           ,rest-name)
154                                          name error-kind error-fun)
155                   (push keyword keys)))
156                ((:auxs)
157                 (push-let-binding (car var) (cadr var) nil))))
158             ((and symbol (not (eql nil)))
159              (case var
160                (&whole
161                 (cond ((cdr rest-of-args)
162                        (setq rest-of-args (cdr rest-of-args))
163                        (process-sublist (car rest-of-args)
164                                         "WHOLE-LIST-" arg-list-name))
165                       (t
166                        (defmacro-error "&WHOLE" error-kind name))))
167                (&environment
168                 (cond (env-illegal
169                        (error "&ENVIRONMENT is not valid with ~S." error-kind))
170                       ((not toplevel)
171                        (error "&ENVIRONMENT is only valid at top level of ~
172                              lambda-list."))
173                       (env-arg-used
174                        (error "Repeated &ENVIRONMENT.")))
175                 (cond ((and (cdr rest-of-args) (symbolp (cadr rest-of-args)))
176                        (setq rest-of-args (cdr rest-of-args))
177                        (check-defmacro-arg (car rest-of-args))
178                        (setq *env-var* (car rest-of-args))
179                        (setq env-arg-used t))
180                       (t
181                        (defmacro-error "&ENVIRONMENT" error-kind name))))
182                ((&rest &body)
183                 (cond ((and (not restp) (cdr rest-of-args))
184                        (setq rest-of-args (cdr rest-of-args))
185                        (setq restp t)
186                        (process-sublist (car rest-of-args) "REST-LIST-" path))
187                       (t
188                        (defmacro-error (symbol-name var) error-kind name))))
189                (&optional
190                 (setq now-processing :optionals))
191                (&key
192                 (setq now-processing :keywords)
193                 (setq rest-name (gensym "KEYWORDS-"))
194                 (push rest-name *ignorable-vars*)
195                 (setq restp t)
196                 (setq key-seen t)
197                 (push-let-binding rest-name path t))
198                (&allow-other-keys
199                 (setq allow-other-keys-p t))
200                (&aux
201                 (setq now-processing :auxs))
202                ;; FIXME: Other lambda list keywords.
203                (t
204                 (case now-processing
205                   ((:required)
206                    (when restp
207                      (defmacro-error "required argument after &REST/&BODY"
208                          error-kind name))
209                    (push-let-binding var `(car ,path) nil)
210                    (setq minimum (1+ minimum)
211                          maximum (1+ maximum)
212                          path `(cdr ,path)))
213                   ((:optionals)
214                    (push-let-binding var `(car ,path) nil `(not (null ,path)))
215                    (setq path `(cdr ,path)
216                          maximum (1+ maximum)))
217                   ((:keywords)
218                    (let ((key (keywordicate var)))
219                      (push-let-binding var
220                                        `(lookup-keyword ,key ,rest-name)
221                                        nil)
222                      (push key keys)))
223                   ((:auxs)
224                    (push-let-binding var nil nil))))))
225             (t
226              (error "non-symbol in lambda-list: ~S" var))))))
227     (let (;; common subexpression, suitable for passing to functions
228           ;; which expect a MAXIMUM argument regardless of whether
229           ;; there actually is a maximum number of arguments
230           ;; (expecting MAXIMUM=NIL when there is no maximum)
231           (explicit-maximum (and (not restp) maximum)))
232       (unless (and restp (zerop minimum))
233         (push `(unless ,(if restp
234                             ;; (If RESTP, then the argument list might be
235                             ;; dotted, in which case ordinary LENGTH won't
236                             ;; work.)
237                             `(list-of-length-at-least-p ,path-0 ,minimum)
238                             `(proper-list-of-length-p ,path-0 ,minimum ,maximum))
239                  ,(if (eq error-fun 'error)
240                       `(arg-count-error ',error-kind ',name ,path-0
241                                         ',lambda-list ,minimum
242                                         ,explicit-maximum)
243                       `(,error-fun 'arg-count-error
244                                    :kind ',error-kind
245                                    ,@(when name `(:name ',name))
246                                    :args ,path-0
247                                    :lambda-list ',lambda-list
248                                    :minimum ,minimum
249                                    :maximum ,explicit-maximum)))
250               *arg-tests*))
251       (when key-seen
252         (let ((problem (gensym "KEY-PROBLEM-"))
253               (info (gensym "INFO-")))
254           (push `(multiple-value-bind (,problem ,info)
255                      (verify-keywords ,rest-name
256                                       ',keys
257                                       ',allow-other-keys-p)
258                    (when ,problem
259                      (,error-fun
260                       'defmacro-lambda-list-broken-key-list-error
261                       :kind ',error-kind
262                       ,@(when name `(:name ',name))
263                       :problem ,problem
264                       :info ,info)))
265                 *arg-tests*)))
266       (values env-arg-used minimum explicit-maximum))))
267
268 ;;; We save space in macro definitions by calling this function.
269 (defun arg-count-error (error-kind name args lambda-list minimum maximum)
270   (let (#-sb-xc-host
271         (sb!debug:*stack-top-hint* (nth-value 1 (find-caller-name-and-frame))))
272     (error 'arg-count-error
273            :kind error-kind
274            :name name
275            :args args
276            :lambda-list lambda-list
277            :minimum minimum
278            :maximum maximum)))
279
280 (defun push-sub-list-binding (variable path object name error-kind error-fun)
281   (check-defmacro-arg variable)
282   (let ((var (gensym "TEMP-")))
283     (push `(,variable
284             (let ((,var ,path))
285               (if (listp ,var)
286                 ,var
287                 (,error-fun 'defmacro-bogus-sublist-error
288                             :kind ',error-kind
289                             ,@(when name `(:name ',name))
290                             :object ,var
291                             :lambda-list ',object))))
292           *system-lets*)))
293
294 (defun push-let-binding (variable path systemp &optional condition
295                                   (init-form *default-default*))
296   (check-defmacro-arg variable)
297   (let ((let-form (if condition
298                       `(,variable (if ,condition ,path ,init-form))
299                       `(,variable ,path))))
300     (if systemp
301       (push let-form *system-lets*)
302       (push let-form *user-lets*))))
303
304 (defun push-optional-binding (value-var init-form supplied-var condition path
305                                         name error-kind error-fun)
306   (unless supplied-var
307     (setq supplied-var (gensym "SUPPLIEDP-")))
308   (push-let-binding supplied-var condition t)
309   (cond ((consp value-var)
310          (let ((whole-thing (gensym "OPTIONAL-SUBLIST-")))
311            (push-sub-list-binding whole-thing
312                                   `(if ,supplied-var ,path ,init-form)
313                                   value-var name error-kind error-fun)
314            (parse-defmacro-lambda-list value-var whole-thing name
315                                        error-kind error-fun)))
316         ((symbolp value-var)
317          (push-let-binding value-var path nil supplied-var init-form))
318         (t
319          (error "illegal optional variable name: ~S" value-var))))
320
321 (defun defmacro-error (problem kind name)
322   (error "illegal or ill-formed ~A argument in ~A~@[ ~S~]"
323          problem kind name))
324
325 (defun check-defmacro-arg (arg)
326   (when (or (and *env-var* (eq arg *env-var*))
327             (member arg *system-lets* :key #'car)
328             (member arg *user-lets* :key #'car))
329     (error "variable ~S occurs more than once" arg)))
330
331 ;;; Determine whether KEY-LIST is a valid list of keyword/value pairs.
332 ;;; Do not signal the error directly, 'cause we don't know how it
333 ;;; should be signaled.
334 (defun verify-keywords (key-list valid-keys allow-other-keys)
335   (do ((already-processed nil)
336        (unknown-keyword nil)
337        (remaining key-list (cddr remaining)))
338       ((null remaining)
339        (if (and unknown-keyword
340                 (not allow-other-keys)
341                 (not (lookup-keyword :allow-other-keys key-list)))
342            (values :unknown-keyword (list unknown-keyword valid-keys))
343            (values nil nil)))
344     (cond ((not (and (consp remaining) (listp (cdr remaining))))
345            (return (values :dotted-list key-list)))
346           ((null (cdr remaining))
347            (return (values :odd-length key-list)))
348           ((or (eq (car remaining) :allow-other-keys)
349                (member (car remaining) valid-keys))
350            (push (car remaining) already-processed))
351           (t
352            (setq unknown-keyword (car remaining))))))
353
354 (defun lookup-keyword (keyword key-list)
355   (do ((remaining key-list (cddr remaining)))
356       ((endp remaining))
357     (when (eq keyword (car remaining))
358       (return (cadr remaining)))))
359
360 (defun keyword-supplied-p (keyword key-list)
361   (do ((remaining key-list (cddr remaining)))
362       ((endp remaining))
363     (when (eq keyword (car remaining))
364       (return t))))