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)
                   body)))
    `(defun ,name ,args
       ,@decl
       (bordeaux-threads:with-lock-held (*request-lock*)
         ,@body))))

      

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

+3


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.

+1


source


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)))
                                        body))
         (just-the-decls (ldiff body just-the-code)))
    (values just-the-decls just-the-code)))

      

Tests:

> (separate-decls-and-body '((declare (optimize (speed 3))) (declare (type)) 1 2 3))
((DECLARE (OPTIMIZE (SPEED 3))) (DECLARE (TYPE))) ;
(1 2 3)

> (separate-decls-and-body '((declare (optimize (speed 3)))))
((DECLARE (OPTIMIZE (SPEED 3)))) ;
NIL

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

> (separate-decls-and-body '(1 2 3))
NIL ;
(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.

+3


source


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))))

      

+1


source







All Articles