Modify the way source files are listed in *SOURCE*
[jscl.git] / jscl.lisp
index 04b9450..9dd2b5a 100644 (file)
--- a/jscl.lisp
+++ b/jscl.lisp
 
 (in-package :jscl)
 
+;;; List of all the source files that need to be compiled, and whether they
+;;; are to be compiled just by the host, by the target JSCL, or by both.
+;;; All files have a `.lisp' extension, and
+;;; are relative to src/
+;;; Subdirectories are indicated by the presence of a list rather than a
+;;; keyword in the second element of the list. For example, this list:
+;;;  (("foo"    :target)
+;;;   ("bar"
+;;;     ("baz"  :host)
+;;;     ("quux" :both)))
+;;; Means that src/foo.lisp and src/bar/quux.lisp need to be compiled in the
+;;; target, and that src/bar/baz.lisp and src/bar/quux.lisp need to be
+;;; compiled in the host
 (defvar *source*
-  '(("boot"             :target)
-    ("compat"           :host)
-    ("utils"            :both)
-    ("numbers"          :target)
-    ("char"             :target)
-    ("list"             :target)
-    ("array"            :target)
-    ("string"           :target)
-    ("sequence"         :target)
-    ("stream"           :target)
-    ("print"            :target)
-    ("package"          :target)
-    ("misc"             :target)
-    ("ffi"              :both)
-    ("read"             :both)
-    ("defstruct"        :both)
-    ("lambda-list"      :both)
-    ("backquote"        :both)
-    ("compiler-codegen" :both)
-    ("compiler"         :both)
-    ("toplevel"         :target)))
+  '(("boot"        :target)
+    ("compat"      :host)
+    ("utils"       :both)
+    ("numbers"     :target)
+    ("char"        :target)
+    ("list"        :target)
+    ("array"       :target)
+    ("string"      :target)
+    ("sequence"    :target)
+    ("stream"      :target)
+    ("print"       :target)
+    ("package"     :target)
+    ("misc"        :target)
+    ("ffi"         :both)
+    ("read"        :both)
+    ("defstruct"   :both)
+    ("lambda-list" :both)
+    ("backquote"   :both)
+    ("compiler"
+     ("codegen"    :both)
+     ("compiler"   :both))
+    ("toplevel"    :target)))
+
+(defun get-files (file-list type dir)
+  "Traverse FILE-LIST and retrieve a list of the files within which match
+   either TYPE or :BOTH, processing subdirectories."
+  (let ((file (car file-list)))
+    (cond
+      ((null file-list)
+       ())
+      ((listp (cadr file))
+       (append
+         (get-files (cdr file)      type (append dir (list (car file))))
+         (get-files (cdr file-list) type dir)))
+      ((member (cadr file) (list type :both))
+       (cons (source-pathname (car file) :directory dir :type "lisp")
+             (get-files (cdr file-list) type dir)))
+      (t
+       (get-files (cdr file-list) type dir)))))
 
 (defmacro do-source (name type &body body)
+  "Iterate over all the source files that need to be compiled in the host or
+   the target, depending on the TYPE argument."
   (unless (member type '(:host :target))
-    (error "TYPE should be one of :HOST or :TARGET"))
-  (let ((file (gensym)))
-    `(dolist (,file *source*)
-       (when (member (cadr ,file) (list :both ,type))
-         (let ((,name (source-pathname (car ,file) :type "lisp")))
-           ,@body)))))
+    (error "TYPE must be one of :HOST or :TARGET, not ~S" type))
+  `(dolist (,name (get-files *source* ,type '(:relative "src")))
+     ,@body))
 
 (defun source-pathname
     (filename &key (directory '(:relative "src")) (type nil) (defaults filename))