560af5c5 |
1 | (defpackage "AUTOEXPORT" |
2 | (:use "COMMON-LISP") |
3 | (:export "LIST-AUTOEXPORTED-SYMBOLS" "LIST-AUTOEXPORTED-SYMBOLS-IN-FILE" |
f3808390 |
4 | "DEFEXPORT" "EXPORT-FROM-FILE" "EXPORT-FROM-FILES" "INTERNAL" |
5 | "WITH-EXPORT-HANDLERS" "EXPORT-HANDLER-MAKUNBOUND" |
db7a1e77 |
6 | "EXPORT-DEFCLASS-FORM" "EXPORT-FROM-SYSTEM")) |
560af5c5 |
7 | |
8 | (in-package "AUTOEXPORT") |
9 | |
10 | (declaim (special *internal*)) |
11 | |
12 | (defvar *export-handlers* (make-hash-table)) |
13 | (defvar *noexport-prefix* #\%) |
14 | |
15 | (defmacro defexport (operator lambda-list &body body) |
16 | `(setf |
17 | (gethash ',operator *export-handlers*) |
18 | #'(lambda ,lambda-list |
19 | ,@body))) |
20 | |
21 | (defmacro internal (&rest symbols) |
22 | (declare (ignore symbols)) |
23 | nil) |
24 | |
f3808390 |
25 | (defun export-handler-makunbound (handler) |
26 | (remhash handler *export-handlers*)) |
27 | |
560af5c5 |
28 | (defun list-autoexported-symbols (form) |
29 | (let ((handler (gethash (first form) *export-handlers*))) |
30 | (when handler |
31 | (let ((export (apply handler (cdr form)))) |
32 | (delete-if |
33 | #'(lambda (symbol) |
34 | (char= (char (string symbol) 0) *noexport-prefix*)) |
35 | (if (atom export) |
36 | (list export) |
37 | export)))))) |
38 | |
39 | (defun export-fname (fname) |
40 | (if (atom fname) |
41 | fname |
42 | (second fname))) |
43 | |
44 | (defun list-autoexported-symbols-in-file (file) |
45 | (let ((*internal* nil)) |
46 | (declare (special *internal*)) |
47 | (with-open-file (in file) |
48 | (labels ((read-file (in) |
49 | (let ((form (read in nil nil))) |
50 | (when form |
51 | (delete-if |
52 | #'(lambda (symbol) |
53 | (member symbol *internal*)) |
54 | (delete-duplicates |
55 | (nconc |
56 | (list-autoexported-symbols form) |
57 | (read-file in)))))))) |
58 | (read-file in))))) |
59 | |
f3808390 |
60 | (defmacro export-from-file (file &optional package) |
61 | (if package |
62 | `(export ',(list-autoexported-symbols-in-file file) ,package) |
63 | `(export ',(list-autoexported-symbols-in-file file)))) |
64 | |
65 | (defmacro export-from-files (files &optional package) |
66 | `(progn |
67 | ,@(loop for file in files collect `(export-from-file ,file ,package)))) |
68 | |
db7a1e77 |
69 | (defmacro export-from-system (&optional package) |
70 | (let ((depends-on (cdar (asdf:component-depends-on asdf:*operation* asdf:*component*)))) |
71 | `(progn |
72 | ,@(loop |
73 | for component in depends-on |
74 | as pathname = (asdf:component-pathname |
75 | (asdf:find-component asdf:*system* component)) |
76 | collect `(export-from-file ,pathname ,package))))) |
77 | |
f3808390 |
78 | (defun copy-hash-table (hash-table) |
79 | (let ((new-hash-table (make-hash-table |
80 | :test (hash-table-test hash-table) |
81 | :size (hash-table-size hash-table)))) |
82 | (maphash |
83 | #'(lambda (key value) |
84 | (setf (gethash key new-hash-table) value)) |
85 | hash-table) |
86 | new-hash-table)) |
87 | |
88 | (defmacro with-export-handlers (&body body) |
89 | `(let ((*export-handlers* (copy-hash-table *export-handlers*))) |
90 | ,@body)) |
91 | |
560af5c5 |
92 | |
93 | ;;;; Exporting standard forms |
94 | |
95 | (defexport defun (fname &rest rest) |
96 | (declare (ignore rest)) |
97 | (export-fname fname)) |
98 | |
99 | (defexport defvar (name &rest rest) |
100 | (declare (ignore rest)) |
101 | name) |
102 | |
103 | (defexport defconstant (name &rest rest) |
104 | (declare (ignore rest)) |
105 | name) |
106 | |
107 | (defexport defparameter (name &rest rest) |
108 | (declare (ignore rest)) |
109 | name) |
110 | |
111 | (defexport defmacro (name &rest rest) |
112 | (declare (ignore rest)) |
113 | name) |
114 | |
115 | (defexport deftype (name &rest rest) |
116 | (declare (ignore rest)) |
117 | name) |
118 | |
f3808390 |
119 | (defun export-defclass-form (class slotdefs &optional (export-slots-p t)) |
560af5c5 |
120 | (cons |
121 | class |
aee2ecd4 |
122 | (apply #'nconc |
123 | (map 'list |
560af5c5 |
124 | #'(lambda (slotdef) |
125 | (if (symbolp slotdef) |
126 | (list slotdef) |
127 | (destructuring-bind |
128 | (name &key reader writer accessor &allow-other-keys) slotdef |
f3808390 |
129 | (delete nil (list (when export-slots-p name) reader (export-fname writer) accessor))))) |
560af5c5 |
130 | slotdefs)))) |
131 | |
aee2ecd4 |
132 | (defexport defclass (class superclasses &optional slotdefs &rest options) |
133 | (declare (ignore superclasses options)) |
134 | (export-defclass-form class slotdefs)) |
135 | |
136 | (defexport define-condition (class superclasses &optional slotdefs &rest options) |
137 | (declare (ignore superclasses options)) |
138 | (export-defclass-form class slotdefs)) |
139 | |
560af5c5 |
140 | (defexport defgeneric (fname &rest args) |
141 | (declare (ignore args)) |
142 | (export-fname fname)) |
143 | |
f3808390 |
144 | ;; (defexport defmethod (name &rest rest) |
145 | ;; (declare (ignore rest)) |
146 | ;; name) |
573086fb |
147 | |
560af5c5 |
148 | (defexport progn (&rest body) |
149 | (apply #'nconc (map 'list #'list-autoexported-symbols body))) |
150 | |
151 | (defexport eval-when (case &rest body) |
152 | (declare (ignore case)) |
153 | (apply #'nconc (map 'list #'list-autoexported-symbols body))) |
154 | |
155 | (defexport internal (&rest symbols) |
156 | (setq *internal* (nconc *internal* symbols)) |
157 | nil) |
158 | |