Neutral way to find DECLARE from body and body

I am writing a macro that generates a call DEFUN

- accordingly, I want to make sure that anything DECLARE

in the body for the macro is placed immediately after DEFUN

. Here's what I have:

(defmacro defsynced (name (&rest args) &body body)
  (let* ((decl (if (eql (caar body) 'cl:declare)
                   (list (car body))))
         (body (if decl
                   (cdr body)
    `(defun ,name ,args
       (bordeaux-threads:with-lock-held (*request-lock*)


Unfortunately this is pretty ugly and isn't necessarily obvious what's going on here. Is there a better way you can think of?


source to share

3 answers

Since parsing declarations can be tricky, there is a library called parse-declarations that helps with it. It is available from Quicklisp .

(ql:quickload "parse-declarations-1.0")


The function is parse-body

especially important for your question.



Your solution is not complete because there may be one or more ads.

While you can use some of the shelf's features to do this, it does provide a good learning curve that can be useful in situations like this.

If you have a list of forms

(alpha beta x epsilon ... omega)


where x is the object of interest by which you want to split the list, you can use a function member

to find the sublist starting with x

and then a function ldiff

to get the prefix of that list (alpha beta)

that excludes (x epsilon omega)

. First step:

(member-if-not (lambda (x) (eq x 'declare)) '(declare declare 3 4 5))

-> (3 4 5)


Of course we're looking for (declare ...)

not declare

. We cannot use :key #'car

for this, because the forms may not match, so:

(member-if-not (lambda (x) (and (consp x) (eq (car x) 'declare)))
               '((declare foo) (declare bar) 3 4 5))
-> (3 4 5)


Now, how to get declarations and other forms yourself:

(defun separate-decls-and-body (body)
  (let* ((just-the-code (member-if-not (lambda (x)
                                         (and (consp x) (eq (car x) 'declare)))
         (just-the-decls (ldiff body just-the-code)))
    (values just-the-decls just-the-code)))



> (separate-decls-and-body '((declare (optimize (speed 3))) (declare (type)) 1 2 3))
(1 2 3)

> (separate-decls-and-body '((declare (optimize (speed 3)))))

> (separate-decls-and-body '())

> (separate-decls-and-body '(1 2 3))
(1 2 3)


Family member

and ldiff

- your friends. ldiff

based on what member

returns a substructure of the original list, not a copy; it simply steps down the list looking for that pointer and returns all previous items as a new list.



There is no answer without a ritual sacrifice to the deity loop


(defun separate-decls-and-body (body)
  (loop for sub-body on body
        for form = (first sub-body) 
        until (or (atom form) (not (eq (first form) 'declare)))
        collecting form into decls
        finally (return (values decls sub-body))))




All Articles