A :files clause and a possible change to parse-component-form

Gary King <[email protected]>
Newsgroups gmane.lisp.cclan.general
Message-ID <[email protected]>
Overall, I think ASDF is very nice. There is one thing, however, which  
I dislike: the amount of boilerplate code involved in defining a system  
with many files when the dependencies are already encoded in the file  
ordering. As an example, I'd rather type

(asdf:defsystem :eksl-utilities-base
   :version "1.0"
   :components ((:files ("package"
                         "l0-utils"
                         "anaphoric"
                         "graham"
                         "feature-case"
                         "macros"
                         "spy"
                         "timeit"
                         "utilities"
                         "string-utilities"
                         "debugging-utils"
                         "day-and-time"
                         "copy"
                         "clos-mop-utils"
                         "clos-utils"
                         "clos-mixins"
                         "class-defs"
                         "indentation"
                         "longest-subsequence"))))

Than

(asdf:defsystem :eksl-utilities-base
   :version "1.0"
   :components ((:FILE "package")
                (:FILE "l0-utils")
                (:FILE "anaphoric")
                (:FILE "graham")
                (:FILE "feature-case")
                (:FILE "macros")
                (:FILE "spy")
                (:FILE "timeit")
                (:FILE "utilities")
                (:FILE "string-utilities")
                (:FILE "debugging-utils")
                (:FILE "day-and-time")
                (:FILE "copy")
                (:FILE "clos-mop-utils")
                (:FILE "clos-utils")
                (:FILE "clos-mixins")
                (:FILE "class-defs")
                (:FILE "indentation")
                (:FILE "longest-subsequence")))

Though there are probably other ways to do this, the easiest way I  
found was to modify parse-component-form to break on the type and then  
call a helper method (parse-component-form-aux) that dispatches on that  
type. When the type is :files, the method simply calls the helper with  
each file; otherwise, parse-component-form-aux does the same work that  
parse-component-form does. Note that I'm not sure how this suggested  
implementation will play with non-Lisp files.

(defun parse-component-form (parent options)
   (destructuring-bind (type datum &rest rest &key
                             depends-on components in-order-to
                             &allow-other-keys)
                       options
     (check-component-input type datum depends-on components in-order-to)

     (apply #'parse-component-form-aux type datum parent rest)))

;;;  
------------------------------------------------------------------------ 
---

(defmethod parse-component-form-aux ((type (eql :files)) files parent  
&rest options
                                      &key &allow-other-keys)
   (loop for file in files collect
         (apply #'parse-component-form-aux :file file parent options)))

;;;  
------------------------------------------------------------------------ 
---

(defmethod parse-component-form-aux ((type symbol) name parent &rest  
options
                                      &key 	
                                      ;; the following list of keywords  
is reproduced below in the
                                      ;; remove-keys form.  important to  
keep them in sync
                                      components pathname  
default-component-class
                                      perform explain output-files  
operation-done-p
                                      depends-on serial in-order-to
                                      ;; list ends
                                      &allow-other-keys)
   (let* ((other-args (remove-keys
                       '(components pathname default-component-class
                         perform explain output-files operation-done-p
                         depends-on serial in-order-to)
                       options))
          (ret
           (or (find-component parent name)
               (make-instance (class-for-type parent type)))))
     (when (boundp '*serial-depends-on*)
       (setf depends-on
             (concatenate 'list *serial-depends-on* depends-on)))
     (apply #'reinitialize-instance
            ret
            :name (coerce-name name)
            :pathname pathname
            :parent parent
            other-args)
     (when (typep ret 'module)
       (setf (module-default-component-class ret)
             (or default-component-class
                 (and (typep parent 'module)
                      (module-default-component-class parent))))
       (let ((*serial-depends-on* nil))
         (setf (module-components ret)
               (loop for c-form in components
                     for c = (parse-component-form ret c-form)
                     append (if (consp c) c (list c))
                     if serial
                     do (push (component-name c) *serial-depends-on*)))))

     (setf (slot-value ret 'in-order-to)
           (union-of-dependencies
            in-order-to
            `((compile-op (compile-op ,@depends-on))
              (load-op (load-op ,@depends-on))))
           (slot-value ret 'do-first) `((compile-op (load-op  
,@depends-on))))

     (loop for (n v) in `((perform ,perform) (explain ,explain)
                          (output-files ,output-files)
                          (operation-done-p ,operation-done-p))
           do (map 'nil
                   ;; this is inefficient as most of the stored
                   ;; methods will not be for this particular gf n
                   ;; But this is hardly performance-critical
                   (lambda (m) (remove-method (symbol-function n) m))
                   (component-inline-methods ret))
           when v
           do (destructuring-bind (op qual (o c) &body body) v
                (pushnew
                 (eval `(defmethod ,n ,qual ((,o ,op) (,c (eql ,ret)))
                          ,@body))
                 (component-inline-methods ret))))
     ret))

-- 
Gary Warren King, Lab Manager
EKSL East, University of Massachusetts * 413 577 0176

In the end, compassion has to be the greatest family value
   -- Billy Bragg
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.