Commit | Line | Data |
---|---|---|
fae90f24 | 1 | #! /bin/sh |
d610d8be | 2 | ":"; ### -*-lisp-*- |
fae90f24 MW |
3 | ":"; CL_SOURCE_REGISTRY=$(pwd)/build/src/:; export CL_SOURCE_REGISTRY |
4 | ":"; exec cl-launch -X -l "sbcl cmucl" -s asdf -i "(sod-exports::main)" -- "$0" "$@" || exit 1 | |
5 | ||
cf268da2 | 6 | (cl:defpackage #:sod-exports |
91d9ba3c MW |
7 | (:use #:common-lisp |
8 | #+cmu #:mop | |
9 | #+sbcl #:sb-mop)) | |
cf268da2 MW |
10 | |
11 | (cl:in-package #:sod-exports) | |
91d9ba3c MW |
12 | (eval-when (:compile-toplevel :load-toplevel :execute) |
13 | (mapc #'asdf:load-system '(:sod :sod-frontend))) | |
cf268da2 | 14 | |
097d5a3e MW |
15 | (defun symbolicate (&rest things) |
16 | (intern (apply #'concatenate 'string (mapcar #'string things)))) | |
17 | ||
18 | (defun incomprehensible-form (head tail) | |
19 | (format *error-output* ";; incomprehensible: ~S~%" (cons head tail))) | |
20 | ||
21 | (defgeneric form-list-exports (head tail) | |
22 | (:method (head tail) | |
23 | (declare (ignore head tail)) | |
24 | nil)) | |
25 | ||
ea28678b | 26 | (defmethod form-list-exports ((head (eql 'cl:export)) tail) |
097d5a3e MW |
27 | (let ((symbols (car tail))) |
28 | (if (and (consp symbols) | |
29 | (eq (car symbols) 'quote)) | |
30 | (let ((thing (cadr symbols))) | |
31 | (if (atom thing) (list thing) thing)) | |
32 | (incomprehensible-form head tail)))) | |
33 | ||
ea28678b | 34 | (defmethod form-list-exports ((head (eql 'sod:definst)) tail) |
097d5a3e | 35 | (destructuring-bind (code (streamvar &key export) args &body body) tail |
34c51b1c | 36 | (declare (ignore streamvar body)) |
097d5a3e | 37 | (and export |
34c51b1c MW |
38 | (list* (symbolicate code '-inst) |
39 | (symbolicate 'make- code '-inst) | |
8db2259b MW |
40 | (labels ((dig (tree path) |
41 | (if (or (atom tree) (null path)) tree | |
42 | (dig (nth (car path) tree) (cdr path)))) | |
43 | (cook (arg) | |
44 | (if (consp arg) (car arg) | |
45 | (let ((name (symbol-name arg))) | |
46 | (if (char= (char name 0) #\%) | |
47 | (intern (subseq name 1)) | |
48 | arg)))) | |
49 | (instify (arg) | |
50 | (symbolicate 'inst- (cook arg)))) | |
51 | (loop with state = :mandatory | |
52 | for arg in args | |
53 | if (and (symbolp arg) | |
54 | (char= (char (symbol-name arg) 0) #\&)) | |
55 | do (setf state arg) | |
56 | else if (member state '(:mandatory &rest)) | |
57 | collect (instify arg) | |
58 | else if (member state '(&optional &aux)) | |
59 | collect (instify (dig arg '(0))) | |
60 | else if (eq state '&key) | |
61 | collect (instify (dig arg '(0 1))) | |
62 | else | |
63 | do (error "Confused by ~S." arg))))))) | |
097d5a3e | 64 | |
ea28678b | 65 | (defmethod form-list-exports ((head (eql 'sod::define-tagged-type)) tail) |
097d5a3e MW |
66 | (destructuring-bind (kind what) tail |
67 | (declare (ignore what)) | |
68 | (list kind | |
69 | (symbolicate 'c- kind '-type) | |
70 | (symbolicate 'make- kind '-type)))) | |
71 | ||
e43d3532 MW |
72 | (defmethod form-list-exports ((head (eql 'sod:defctype)) tail) |
73 | (destructuring-bind (names value &key export) tail | |
74 | (declare (ignore value)) | |
75 | (let ((names (if (listp names) names (list names)))) | |
76 | (and export | |
77 | (list* (symbolicate 'c-type- (car names)) names))))) | |
78 | ||
79 | (defmethod form-list-exports ((head (eql 'sod:define-simple-c-type)) tail) | |
80 | (destructuring-bind (names type &key export) tail | |
81 | (declare (ignore type)) | |
82 | (let ((names (if (listp names) names (list names)))) | |
83 | (and export | |
84 | (list* (symbolicate 'c-type- (car names)) names))))) | |
85 | ||
ea28678b | 86 | (defmethod form-list-exports ((head (eql 'cl:macrolet)) tail) |
097d5a3e MW |
87 | (mapcan #'form-exports (cdr tail))) |
88 | ||
ea28678b | 89 | (defmethod form-list-exports ((head (eql 'cl:eval-when)) tail) |
fdc3e506 MW |
90 | (mapcan #'form-exports (cdr tail))) |
91 | ||
ea28678b | 92 | (defmethod form-list-exports ((head (eql 'cl:progn)) tail) |
097d5a3e MW |
93 | (mapcan #'form-exports tail)) |
94 | ||
95 | (defgeneric form-exports (form) | |
96 | (:method (form) nil) | |
97 | (:method ((form cons)) (form-list-exports (car form) (cdr form)))) | |
98 | ||
99 | (defgeneric list-exports (thing)) | |
100 | ||
101 | (defmethod list-exports ((stream stream)) | |
102 | (loop with eof = '#:eof | |
103 | for form = (read stream nil eof) | |
104 | until (eq form eof) | |
105 | when (consp form) nconc (form-exports form))) | |
106 | ||
107 | (defmethod list-exports ((path pathname)) | |
108 | (mapcar (lambda (each) | |
109 | (cons each (with-open-file (stream each) (list-exports stream)))) | |
110 | (directory (merge-pathnames path #p"*.lisp")))) | |
111 | ||
112 | (defmethod list-exports ((path string)) | |
113 | (list-exports (pathname path))) | |
114 | ||
115 | (defun list-exported-symbols (package) | |
116 | (sort (loop for s being the external-symbols of package collect s) | |
117 | #'string< :key #'symbol-name)) | |
118 | ||
c2937ad0 MW |
119 | (defun list-all-symbols (package) |
120 | (let ((externs (make-hash-table))) | |
121 | (dolist (sym (list-exported-symbols package)) | |
122 | (setf (gethash sym externs) t)) | |
123 | (sort (loop for s being the symbols of package | |
124 | when (or (not (exported-symbol-p s)) | |
125 | (gethash s externs)) | |
126 | collect s) | |
127 | #'string< :key #'symbol-name))) | |
128 | ||
097d5a3e MW |
129 | (defun find-symbol-homes (paths package) |
130 | (let* ((symbols (list-exported-symbols package)) | |
ea28678b MW |
131 | (exports-alist (let ((*package* package)) |
132 | (mapcan #'list-exports paths))) | |
097d5a3e MW |
133 | (homes (make-hash-table :test #'equal))) |
134 | (dolist (assoc exports-alist) | |
135 | (let ((home (car assoc))) | |
136 | (dolist (symbol (cdr assoc)) | |
137 | (let ((name (symbol-name symbol))) | |
de8f0794 | 138 | (unless (nth-value 1 (find-symbol name package)) |
097d5a3e MW |
139 | (format *error-output* ";; unexported: ~S~%" symbol)) |
140 | (setf (gethash name homes) home))))) | |
141 | (dolist (symbol symbols) | |
142 | (unless (gethash (symbol-name symbol) homes) | |
143 | (format *error-output* ";; mysterious: ~S~%" symbol))) | |
144 | exports-alist)) | |
145 | ||
146 | (defun boring-setf-expansion-p (symbol) | |
147 | (multiple-value-bind (temps args stores store fetch) | |
148 | (ignore-errors (get-setf-expansion (list symbol))) | |
149 | (declare (ignore temps args stores fetch)) | |
150 | (and (consp store) | |
151 | (eq (car store) 'funcall) | |
152 | (consp (cdr store)) (consp (cadr store)) | |
153 | (eq (caadr store) 'function) | |
154 | (let ((func (cadadr store))) | |
155 | (and (consp func) (consp (cdr func)) | |
156 | (eq (car func) 'setf)))))) | |
157 | ||
158 | (defun specialized-on-p (func arg what) | |
159 | (some (lambda (method) | |
91d9ba3c MW |
160 | (let ((spec (nth arg (method-specializers method)))) |
161 | (and (typep spec 'eql-specializer) | |
162 | (eql (eql-specializer-object spec) what)))) | |
163 | (generic-function-methods func))) | |
097d5a3e MW |
164 | |
165 | (defun categorize (symbol) | |
166 | (let ((things nil)) | |
167 | (when (boundp symbol) | |
168 | (push (if (constantp symbol) :constant :variable) things)) | |
169 | (when (fboundp symbol) | |
170 | (push (cond ((macro-function symbol) :macro) | |
171 | ((typep (fdefinition symbol) 'generic-function) | |
172 | :generic) | |
173 | (t :function)) | |
174 | things) | |
e9f884f9 MW |
175 | (etypecase (ignore-errors (fdefinition (list 'setf symbol))) |
176 | (generic-function (push :setf-generic things)) | |
177 | (function (push :setf-function things)) | |
178 | (null))) | |
097d5a3e MW |
179 | (when (find-class symbol nil) |
180 | (push :class things)) | |
181 | (when (or (specialized-on-p #'sod:expand-c-type-spec 0 symbol) | |
182 | (specialized-on-p #'sod:expand-c-type-form 0 symbol)) | |
183 | (push :c-type things)) | |
184 | (when (or (specialized-on-p #'sod-parser:expand-parser-spec 1 symbol) | |
185 | (specialized-on-p #'sod-parser:expand-parser-form 1 symbol)) | |
186 | (push :parser things)) | |
61982981 MW |
187 | (when (get symbol 'optparse::opthandler) |
188 | (push :opthandler things)) | |
189 | (when (get symbol 'optparse::optmacro) | |
190 | (push :optmacro things)) | |
097d5a3e MW |
191 | (nreverse things))) |
192 | ||
193 | (defun categorize-symbols (paths package) | |
194 | (mapcar (lambda (assoc) | |
195 | (let ((home (car assoc)) | |
8922d110 MW |
196 | (symbols (delete-duplicates |
197 | (sort (mapcan (lambda (sym) | |
198 | (multiple-value-bind | |
199 | (symbol foundp) | |
200 | (find-symbol | |
201 | (symbol-name sym) | |
202 | package) | |
203 | (and foundp (list symbol)))) | |
204 | (cdr assoc)) | |
205 | #'string< :key #'symbol-name)))) | |
097d5a3e MW |
206 | (cons home (mapcar (lambda (symbol) |
207 | (cons symbol (categorize symbol))) | |
208 | symbols)))) | |
209 | ||
649798ab | 210 | (find-symbol-homes paths package))) |
097d5a3e MW |
211 | |
212 | (defun best-package-name (package) | |
d185dba5 MW |
213 | |
214 | ;; We pick the shortest one. Strangely, there's no `find minimal thing | |
215 | ;; according to this valuation' function in Common Lisp. | |
216 | (loop with best = (package-name package) | |
217 | with best-length = (length best) | |
218 | for name in (package-nicknames package) | |
219 | for name-length = (length name) | |
220 | when (< name-length best-length) | |
221 | do (setf best name | |
222 | best-length name-length) | |
223 | finally (return best))) | |
097d5a3e MW |
224 | |
225 | (defvar charbuf-size 0) | |
226 | ||
b9d603a0 MW |
227 | (defun exported-symbol-p (symbol &optional (package (symbol-package symbol))) |
228 | (and package | |
229 | (multiple-value-bind (sym how) | |
230 | (find-symbol (symbol-name symbol) package) | |
231 | (and (eq sym symbol) | |
232 | (eq how :external))))) | |
233 | ||
765231c0 MW |
234 | (defun downcase-or-escape (name) |
235 | (if (every (lambda (char) | |
236 | (or (upper-case-p char) | |
237 | (digit-char-p char) | |
238 | (member char '(#\% #\+ #\- #\* #\/ #\= #\[ #\] #\?)))) | |
239 | name) | |
240 | (string-downcase name) | |
241 | (with-output-to-string (out) | |
242 | (write-char #\| out) | |
243 | (map nil (lambda (char) | |
244 | (when (or (char= char #\|) | |
245 | (char= char #\\)) | |
246 | (write-char #\\ out)) | |
247 | (write-char char out)) | |
248 | name) | |
249 | (write-char #\| out)))) | |
250 | ||
097d5a3e | 251 | (defun pretty-symbol-name (symbol package) |
b9d603a0 MW |
252 | (let ((pkg (symbol-package symbol)) |
253 | (exportp (exported-symbol-p symbol))) | |
765231c0 | 254 | (format nil "~:[~A:~:[:~;~]~;~2*~]~A" |
ed006915 | 255 | (and exportp (eq pkg package)) |
b9d603a0 MW |
256 | (cond ((keywordp symbol) "") |
257 | ((eq pkg nil) "#") | |
765231c0 MW |
258 | (t (downcase-or-escape (best-package-name pkg)))) |
259 | (or exportp (null pkg)) | |
260 | (downcase-or-escape (symbol-name symbol))))) | |
097d5a3e | 261 | |
b8eeeb37 MW |
262 | (deftype interesting-class () |
263 | '(or standard-class | |
264 | structure-class | |
265 | #.(class-name (class-of (find-class 'condition))))) | |
266 | ||
097d5a3e MW |
267 | (defun analyse-classes (package) |
268 | (setf package (find-package package)) | |
269 | (let ((classes (mapcan (lambda (symbol) | |
270 | (let ((class (find-class symbol nil))) | |
271 | (and class | |
b8eeeb37 | 272 | (typep class 'interesting-class) |
097d5a3e MW |
273 | (list class)))) |
274 | (list-exported-symbols package))) | |
275 | (subs (make-hash-table))) | |
276 | (let ((done (make-hash-table))) | |
277 | (labels ((walk-up (class) | |
278 | (unless (gethash class done) | |
91d9ba3c | 279 | (dolist (super (class-direct-superclasses class)) |
097d5a3e MW |
280 | (push class (gethash super subs)) |
281 | (walk-up super)) | |
282 | (setf (gethash class done) t)))) | |
283 | (dolist (class classes) | |
284 | (walk-up class)))) | |
285 | (labels ((walk-down (this super depth) | |
286 | (format t "~v,0T~A~@[ [~{~A~^ ~}]~]~%" | |
287 | (* 2 depth) | |
288 | (pretty-symbol-name (class-name this) package) | |
289 | (mapcar (lambda (class) | |
290 | (pretty-symbol-name (class-name class) | |
291 | package)) | |
292 | (remove super | |
91d9ba3c | 293 | (class-direct-superclasses this)))) |
7a35400d MW |
294 | (dolist (sub (sort (copy-list (gethash this subs)) |
295 | #'string< :key #'class-name)) | |
097d5a3e MW |
296 | (walk-down sub this (1+ depth))))) |
297 | (walk-down (find-class t) nil 0)))) | |
298 | ||
b9d603a0 MW |
299 | (defmacro deep-compare ((left right) &body body) |
300 | (let ((block (gensym "BLOCK-")) (func (gensym "FUNC-")) | |
301 | (l (gensym "LEFT-")) (r (gensym "RIGHT-"))) | |
302 | `(macrolet ((focus (expr &body body) | |
303 | `(flet ((,',func (it) ,expr)) | |
304 | (let ((,',l (,',func ,',l)) | |
305 | (,',r (,',func ,',r))) | |
306 | ,@body))) | |
307 | (update (expr) | |
308 | `(flet ((,',func (it) ,expr)) | |
309 | (psetf ,',l (,',func ,',l) | |
310 | ,',r (,',func ,',r)))) | |
311 | (compare (expr) | |
312 | `(cond ((let ((left ,',l) (right ,',r)) ,expr) | |
313 | (return-from ,',block t)) | |
314 | ((let ((right ,',l) (left ,',r)) ,expr) | |
315 | (return-from ,',block nil)))) | |
316 | (typesw (&rest clauses) | |
317 | (labels ((iter (clauses) | |
318 | (if (null clauses) | |
319 | 'nil | |
320 | (destructuring-bind (type &rest body) | |
321 | (car clauses) | |
322 | (if (eq type t) | |
323 | `(progn ,@body) | |
324 | `(if (typep ,',l ',type) | |
325 | (if (typep ,',r ',type) | |
326 | (progn ,@body) | |
327 | (return-from ,',block t)) | |
328 | (if (typep ,',r ',type) | |
329 | (return-from ,',block nil) | |
330 | ,(iter (cdr clauses))))))))) | |
331 | (iter clauses)))) | |
332 | (let ((,l ,left) (,r ,right)) | |
333 | (block ,block | |
334 | ,@body))))) | |
335 | ||
336 | (defun order-specializers (la lb) | |
337 | (deep-compare (la lb) | |
338 | (loop (typesw (null (return nil))) | |
339 | (focus (car it) | |
91d9ba3c MW |
340 | (typesw (eql-specializer |
341 | (focus (eql-specializer-object it) | |
b9d603a0 MW |
342 | (typesw (keyword |
343 | (compare (string< left right))) | |
344 | (symbol | |
345 | (focus (package-name (symbol-package it)) | |
346 | (compare (string< left right))) | |
347 | (compare (string< left right))) | |
348 | (t | |
349 | (focus (with-output-to-string (out) | |
350 | (prin1 it out) | |
351 | (write-char #\nul)) | |
352 | (compare (string< left right))))))) | |
353 | (class | |
354 | (focus (class-name it) | |
355 | (focus (package-name (symbol-package it)) | |
356 | (compare (string< left right))) | |
357 | (compare (string< left right)))) | |
358 | (t | |
359 | (error "unexpected things")))) | |
360 | (update (cdr it))))) | |
361 | ||
a535feed MW |
362 | (defun analyse-generic-functions (package) |
363 | (setf package (find-package package)) | |
364 | (flet ((function-name-core (name) | |
e36ab294 MW |
365 | (typecase name |
366 | (symbol (values name t)) | |
367 | ((cons (eql setf) t) (values (cadr name) t)) | |
368 | (t (values nil nil))))) | |
a535feed MW |
369 | (let ((methods (make-hash-table)) |
370 | (functions (make-hash-table)) | |
371 | (externs (make-hash-table))) | |
372 | (dolist (symbol (list-exported-symbols package)) | |
373 | (setf (gethash symbol externs) t)) | |
374 | (dolist (symbol (list-exported-symbols package)) | |
375 | (flet ((dofunc (func) | |
376 | (when (typep func 'generic-function) | |
377 | (setf (gethash func functions) t) | |
91d9ba3c | 378 | (dolist (method (generic-function-methods func)) |
a535feed MW |
379 | (setf (gethash method methods) t))))) |
380 | (dofunc (and (fboundp symbol) (fdefinition symbol))) | |
381 | (dofunc (ignore-errors (fdefinition (list 'setf symbol))))) | |
382 | (when (eq (symbol-package symbol) package) | |
383 | (let ((class (find-class symbol nil))) | |
384 | (when class | |
385 | (dolist | |
91d9ba3c | 386 | (func (specializer-direct-generic-functions class)) |
e36ab294 MW |
387 | (multiple-value-bind (name knownp) |
388 | (function-name-core (generic-function-name func)) | |
389 | (when (and knownp | |
390 | (or (not (eq (symbol-package name) package)) | |
391 | (gethash name externs))) | |
a535feed | 392 | (setf (gethash func functions) t) |
91d9ba3c | 393 | (dolist (method (specializer-direct-methods class)) |
a535feed MW |
394 | (setf (gethash method methods) t))))))))) |
395 | (let ((funclist nil)) | |
396 | (maphash (lambda (func value) | |
397 | (declare (ignore value)) | |
398 | (push func funclist)) | |
399 | functions) | |
400 | (setf funclist (sort funclist | |
401 | (lambda (a b) | |
402 | (let ((core-a (function-name-core a)) | |
403 | (core-b (function-name-core b))) | |
404 | (if (eq core-a core-b) | |
405 | (and (atom a) (consp b)) | |
406 | (string< core-a core-b)))) | |
91d9ba3c | 407 | :key #'generic-function-name)) |
a535feed | 408 | (dolist (function funclist) |
91d9ba3c | 409 | (let ((name (generic-function-name function))) |
a535feed MW |
410 | (etypecase name |
411 | (symbol | |
412 | (format t "~A~%" (pretty-symbol-name name package))) | |
413 | ((cons (eql setf) t) | |
414 | (format t "(setf ~A)~%" | |
415 | (pretty-symbol-name (cadr name) package))))) | |
b9d603a0 | 416 | (dolist (method (sort (copy-list |
91d9ba3c | 417 | (generic-function-methods function)) |
b9d603a0 | 418 | #'order-specializers |
91d9ba3c | 419 | :key #'method-specializers)) |
a535feed | 420 | (when (gethash method methods) |
4b0283c7 | 421 | (format t "~2T~{~A~^ ~}~@[ [~{~(~S~)~^ ~}]~]~%" |
a535feed MW |
422 | (mapcar |
423 | (lambda (spec) | |
424 | (etypecase spec | |
425 | (class | |
426 | (let ((name (class-name spec))) | |
427 | (if (eq name t) "t" | |
428 | (pretty-symbol-name name package)))) | |
91d9ba3c MW |
429 | (eql-specializer |
430 | (let ((obj (eql-specializer-object spec))) | |
a535feed MW |
431 | (format nil "(eql ~A)" |
432 | (if (symbolp obj) | |
433 | (pretty-symbol-name obj package) | |
434 | obj)))))) | |
4b0283c7 MW |
435 | (method-specializers method)) |
436 | (method-qualifiers method))))))))) | |
a535feed | 437 | |
4b8e5c03 MW |
438 | (defun check-slot-names (package) |
439 | (setf package (find-package package)) | |
c2937ad0 | 440 | (let* ((symbols (list-all-symbols package)) |
4b8e5c03 MW |
441 | (classes (mapcan (lambda (symbol) |
442 | (when (eq (symbol-package symbol) package) | |
443 | (let ((class (find-class symbol nil))) | |
444 | (and class (list class))))) | |
445 | symbols)) | |
446 | (offenders (mapcan | |
447 | (lambda (class) | |
448 | (let* ((slot-names | |
91d9ba3c MW |
449 | (mapcar #'slot-definition-name |
450 | (class-direct-slots class))) | |
b9d603a0 | 451 | (exported (remove-if |
4b8e5c03 | 452 | (lambda (sym) |
211bfc14 MW |
453 | (or (not (symbol-package sym)) |
454 | (and (not (exported-symbol-p | |
455 | sym)) | |
456 | (eq (symbol-package sym) | |
457 | package)))) | |
4b8e5c03 MW |
458 | slot-names))) |
459 | (and exported | |
460 | (list (cons (class-name class) | |
461 | exported))))) | |
462 | classes)) | |
463 | (bad-words (remove-duplicates (mapcan (lambda (list) | |
464 | (copy-list (cdr list))) | |
465 | offenders)))) | |
466 | (values offenders bad-words))) | |
467 | ||
097d5a3e MW |
468 | (defun report-symbols (paths package) |
469 | (setf package (find-package package)) | |
470 | (format t "~A~%Package `~(~A~)'~2%" | |
471 | (make-string 77 :initial-element #\-) | |
472 | (package-name package)) | |
b9d603a0 MW |
473 | (dolist (assoc (sort (categorize-symbols paths package) #'string< |
474 | :key (lambda (assoc) | |
475 | (file-namestring (car assoc))))) | |
097d5a3e MW |
476 | (when (cdr assoc) |
477 | (format t "~A~%" (file-namestring (car assoc))) | |
478 | (dolist (def (cdr assoc)) | |
479 | (let ((sym (car def))) | |
480 | (format t " ~A~@[~48T~{~(~A~)~^ ~}~]~%" | |
481 | (pretty-symbol-name sym package) | |
482 | (cdr def)))) | |
483 | (terpri))) | |
4b8e5c03 MW |
484 | (multiple-value-bind (alist names) (check-slot-names package) |
485 | (when names | |
486 | (format t "Leaked slot names: ~{~A~^, ~}~%" | |
487 | (mapcar (lambda (name) (pretty-symbol-name name package)) | |
488 | names)) | |
489 | (dolist (assoc alist) | |
490 | (format t "~2T~A: ~{~A~^, ~}~%" | |
491 | (pretty-symbol-name (car assoc) package) | |
492 | (mapcar (lambda (name) (pretty-symbol-name name package)) | |
493 | (cdr assoc)))) | |
494 | (terpri))) | |
388caffa | 495 | (format t "Classes:~%") |
097d5a3e | 496 | (analyse-classes package) |
a535feed MW |
497 | (terpri) |
498 | (format t "Methods:~%") | |
499 | (analyse-generic-functions package) | |
097d5a3e MW |
500 | (terpri)) |
501 | ||
cf268da2 | 502 | (export 'report-project-symbols) |
097d5a3e MW |
503 | (defun report-project-symbols () |
504 | (labels ((components (comp) | |
e390f747 | 505 | (asdf:component-children comp)) |
097d5a3e | 506 | (files (comp) |
7a35400d | 507 | (sort (remove-if-not (lambda (comp) |
b9d603a0 | 508 | (typep comp 'asdf:cl-source-file)) |
7a35400d MW |
509 | (components comp)) |
510 | #'string< :key #'asdf:component-name)) | |
097d5a3e | 511 | (by-name (comp name) |
e390f747 | 512 | (gethash name (asdf:component-children-by-name comp))) |
097d5a3e | 513 | (file-name (file) |
e390f747 | 514 | (slot-value file 'asdf/component:absolute-pathname))) |
097d5a3e MW |
515 | (let* ((sod (asdf:find-system "sod")) |
516 | (parser-files (files (by-name sod "parser"))) | |
517 | (utilities (by-name sod "utilities")) | |
61982981 | 518 | (sod-frontend (asdf:find-system "sod-frontend")) |
4d757a73 | 519 | (optparse (by-name sod "optparse")) |
6ac5b807 | 520 | (frontend (by-name sod-frontend "frontend")) |
4d757a73 | 521 | (sod-files (set-difference (files sod) (list optparse utilities)))) |
097d5a3e | 522 | (report-symbols (mapcar #'file-name sod-files) "SOD") |
6ac5b807 | 523 | (report-symbols (mapcar #'file-name (list frontend)) "SOD-FRONTEND") |
097d5a3e | 524 | (report-symbols (mapcar #'file-name parser-files) "SOD-PARSER") |
61982981 | 525 | (report-symbols (mapcar #'file-name (list optparse)) "OPTPARSE") |
097d5a3e | 526 | (report-symbols (mapcar #'file-name (list utilities)) "SOD-UTILITIES")))) |
1c1a9bf1 | 527 | |
fae90f24 MW |
528 | (defun main () |
529 | (with-open-file (*standard-output* #p"doc/SYMBOLS" | |
530 | :direction :output | |
531 | :if-exists :supersede | |
532 | :if-does-not-exist :create) | |
533 | (report-project-symbols))) | |
534 | ||
535 | #+interactive (main) |