Dawid Romanowski
Dawid Romanowski

Reputation: 31

Lisp - "case" macro implementation

I'm wondering how the case macro works, but just expanding it is not enough. How does it generate the cond statement without knowing how many arguments there are? Does it use a loop or something? And if so then why does it not show up when i run macroexpand.

I need to write something that works in a similar way, that's why I ask.

Upvotes: 1

Views: 346

Answers (1)

sds
sds

Reputation: 60004

Yes you would need to use iteration - one of loop, do, mapcar &c (or recursion).

Take a look at, e.g., CLISP's implementation of case:

(defun case-expand (whole-form form-name test keyform clauses)
  (let ((var (gensym (string-concat (symbol-name form-name) "-KEY-"))))
    `(let ((,var ,keyform))
      (cond
        ,@(maplist
           #'(lambda (remaining-clauses)
               (let ((clause (first remaining-clauses))
                     (remaining-clauses (rest remaining-clauses)))
                 (unless (consp clause)
                   (error-of-type 'source-program-error
                     :form whole-form
                     :detail clause
                     (TEXT "~S: missing key list")
                     form-name))
                 (let ((keys (first clause)))
                   `(,(cond ((or (eq keys 'T) (eq keys 'OTHERWISE))
                             (if remaining-clauses
                                 (error-of-type 'source-program-error
                                   :form whole-form
                                   :detail clause
                                   (TEXT "~S: the ~S clause must be the last one")
                                   form-name keys)
                                 't))
                            ((listp keys)
                             `(or ,@(mapcar #'(lambda (key)
                                                `(,test ,var ',key))
                                            keys)))
                            (t `(,test ,var ',keys)))
                     ,@(rest clause)))))
           clauses)))))

(defmacro case (&whole whole-form
                keyform &body clauses)
  (case-expand whole-form 'case 'eql keyform clauses))

Upvotes: 1

Related Questions