D Herring wrote:
> Numeromancer wrote:
>> Usually, the last thing I do when making a package is putting together
>> the
>> :export list. I find this tedious. Most of the time, I know which
>> symbols I
>> want to export as I am define them. Defining the
>>
>> (defmacro def(un|var|paramater|const|macro|...)-export (name ...)...)
>> `(progn
>> (defun ,name ...)
>> (export ',name))
>>
>> in a utility package seems like a good idea, (sorta like screamer's
>> defX-compile-time) but I have a nagging fear that the appeal of a neat
>> macro is
>> causing me to overlook something. I know most readers of the code
>> will expect
>> to find all exported symbols in defpackage, but that can be fixed with a
>> comment. I wanted to know if there were any technical problems which
>> I might
>> encounter.
>>
>> So I ask: are there? Or should I just tell my nag to shut up?
>
> Another approach is to write a function that scans source files and
> creates the export list for you:
>
> ** begin test.lisp **
> :export
> (defun collect-exports (filename)
> (let ((*readtable* (copy-readtable nil)))
> ;; preserve case
> (setf (readtable-case *readtable*) :preserve)
> (with-open-file (file filename)
> (do ((line (read file nil nil)
> (read file nil nil))
> (flag nil)
> (list nil))
> ((not line)
> (sort list #'string<))
> (if flag
> ;; check for def-forms
> (progn
> (setf flag nil)
> (when (listp line)
> (let ((key (string-upcase (symbol-name (car line)))))
> (when (or (string= key "DEFCONSTANT")
> (string= key "DEFUN")
> (string= key "DEFMACRO")
> (string= key "DEFPARAMETER")
> (string= key "DEFVAR"))
> (push (cadr line) list)))))
> ;; check for :export flag
> (setf flag (unless (listp line)
> (string= (string-upcase (symbol-name line))
> "EXPORT"))))))))
>
> :export
> (defun test (x)
> (+ x 1))
>
> (defun test2 (x)
> (+ x 2))
>
> ;; test
> ;; (format t "(:export ~{:~A~^ ~})~%" (collect-exports "test.lisp"))
> ** end test.lisp **
>
> I'd recommend calling COLLECT-EXPORTS manually; but you could go crazy
> and try
> ** begin package.lisp **
> (defpackage :package
> (:use :cl)
> #.(read-from-string
> (format nil
> "(:export ~{:~A~^ ~})~%"
> (collect-exports "test.lisp"))))
> ** end package.lisp **
> but don't complain when the paths aren't right or you accidentally cause
> an infinite loop.
>
> - Daniel
> [Breaking from tradition, the above code was actually lightly tested.]
This is interesting, but I don't think I'd do this. It looks, uh, dodgy. And
it doesn't really give you back what you've taken away.
Thanks,
Tim S