doc/list-exports.lisp: Sort sibling classes by name in the tree.
[sod] / doc / list-exports.lisp
CommitLineData
097d5a3e
MW
1(defun symbolicate (&rest things)
2 (intern (apply #'concatenate 'string (mapcar #'string things))))
3
4(defun incomprehensible-form (head tail)
5 (format *error-output* ";; incomprehensible: ~S~%" (cons head tail)))
6
7(defgeneric form-list-exports (head tail)
8 (:method (head tail)
9 (declare (ignore head tail))
10 nil))
11
12(defmethod form-list-exports ((head (eql 'export)) tail)
13 (let ((symbols (car tail)))
14 (if (and (consp symbols)
15 (eq (car symbols) 'quote))
16 (let ((thing (cadr symbols)))
17 (if (atom thing) (list thing) thing))
18 (incomprehensible-form head tail))))
19
20(defmethod form-list-exports ((head (eql 'definst)) tail)
21 (destructuring-bind (code (streamvar &key export) args &body body) tail
22 (declare (ignore streamvar args body))
23 (and export
24 (list (symbolicate code '-inst)
25 (symbolicate 'make- code '-inst)))))
26
27(defmethod form-list-exports ((head (eql 'define-tagged-type)) tail)
28 (destructuring-bind (kind what) tail
29 (declare (ignore what))
30 (list kind
31 (symbolicate 'c- kind '-type)
32 (symbolicate 'make- kind '-type))))
33
34(defmethod form-list-exports ((head (eql 'macrolet)) tail)
35 (mapcan #'form-exports (cdr tail)))
36
fdc3e506
MW
37(defmethod form-list-exports ((head (eql 'eval-when)) tail)
38 (mapcan #'form-exports (cdr tail)))
39
097d5a3e
MW
40(defmethod form-list-exports ((head (eql 'progn)) tail)
41 (mapcan #'form-exports tail))
42
43(defgeneric form-exports (form)
44 (:method (form) nil)
45 (:method ((form cons)) (form-list-exports (car form) (cdr form))))
46
47(defgeneric list-exports (thing))
48
49(defmethod list-exports ((stream stream))
50 (loop with eof = '#:eof
51 for form = (read stream nil eof)
52 until (eq form eof)
53 when (consp form) nconc (form-exports form)))
54
55(defmethod list-exports ((path pathname))
56 (mapcar (lambda (each)
57 (cons each (with-open-file (stream each) (list-exports stream))))
58 (directory (merge-pathnames path #p"*.lisp"))))
59
60(defmethod list-exports ((path string))
61 (list-exports (pathname path)))
62
63(defun list-exported-symbols (package)
64 (sort (loop for s being the external-symbols of package collect s)
65 #'string< :key #'symbol-name))
66
67(defun find-symbol-homes (paths package)
68 (let* ((symbols (list-exported-symbols package))
69 (exports-alist (mapcan #'list-exports paths))
70 (homes (make-hash-table :test #'equal)))
71 (dolist (assoc exports-alist)
72 (let ((home (car assoc)))
73 (dolist (symbol (cdr assoc))
74 (let ((name (symbol-name symbol)))
de8f0794 75 (unless (nth-value 1 (find-symbol name package))
097d5a3e
MW
76 (format *error-output* ";; unexported: ~S~%" symbol))
77 (setf (gethash name homes) home)))))
78 (dolist (symbol symbols)
79 (unless (gethash (symbol-name symbol) homes)
80 (format *error-output* ";; mysterious: ~S~%" symbol)))
81 exports-alist))
82
83(defun boring-setf-expansion-p (symbol)
84 (multiple-value-bind (temps args stores store fetch)
85 (ignore-errors (get-setf-expansion (list symbol)))
86 (declare (ignore temps args stores fetch))
87 (and (consp store)
88 (eq (car store) 'funcall)
89 (consp (cdr store)) (consp (cadr store))
90 (eq (caadr store) 'function)
91 (let ((func (cadadr store)))
92 (and (consp func) (consp (cdr func))
93 (eq (car func) 'setf))))))
94
95(defun specialized-on-p (func arg what)
96 (some (lambda (method)
97 (let ((spec (nth arg (sb-mop:method-specializers method))))
98 (and (typep spec 'sb-mop:eql-specializer)
99 (eql (sb-mop:eql-specializer-object spec) what))))
100 (sb-mop:generic-function-methods func)))
101
102(defun categorize (symbol)
103 (let ((things nil))
104 (when (boundp symbol)
105 (push (if (constantp symbol) :constant :variable) things))
106 (when (fboundp symbol)
107 (push (cond ((macro-function symbol) :macro)
108 ((typep (fdefinition symbol) 'generic-function)
109 :generic)
110 (t :function))
111 things)
112 (when (or ;;(not (boring-setf-expansion-p symbol))
113 (ignore-errors (fdefinition (list 'setf symbol))))
114 (push :setf things)))
115 (when (find-class symbol nil)
116 (push :class things))
117 (when (or (specialized-on-p #'sod:expand-c-type-spec 0 symbol)
118 (specialized-on-p #'sod:expand-c-type-form 0 symbol))
119 (push :c-type things))
120 (when (or (specialized-on-p #'sod-parser:expand-parser-spec 1 symbol)
121 (specialized-on-p #'sod-parser:expand-parser-form 1 symbol))
122 (push :parser things))
123 (nreverse things)))
124
125(defun categorize-symbols (paths package)
126 (mapcar (lambda (assoc)
127 (let ((home (car assoc))
128 (symbols (sort (mapcan (lambda (sym)
129 (multiple-value-bind
130 (symbol foundp)
131 (find-symbol (symbol-name sym)
132 package)
133 (and foundp (list symbol))))
134 (cdr assoc))
135 #'string< :key #'symbol-name)))
136 (cons home (mapcar (lambda (symbol)
137 (cons symbol (categorize symbol)))
138 symbols))))
139
649798ab 140 (find-symbol-homes paths package)))
097d5a3e
MW
141
142(defun best-package-name (package)
143 (car (sort (cons (package-name package)
144 (copy-list (package-nicknames package)))
145 #'< :key #'length)))
146
147(defvar charbuf-size 0)
148
149(defun pretty-symbol-name (symbol package)
150 (let* ((pkg (symbol-package symbol))
151 (exportp (member symbol (list-exported-symbols pkg))))
152 (format nil "~(~:[~A:~:[:~;~]~;~2*~]~A~)"
153 (and exportp (eq pkg package)) (best-package-name pkg)
154 exportp (symbol-name symbol))))
155
156(defun analyse-classes (package)
157 (setf package (find-package package))
158 (let ((classes (mapcan (lambda (symbol)
159 (let ((class (find-class symbol nil)))
160 (and class
161 (typep class '(or standard-class
162 structure-class))
163 (list class))))
164 (list-exported-symbols package)))
165 (subs (make-hash-table)))
166 (let ((done (make-hash-table)))
167 (labels ((walk-up (class)
168 (unless (gethash class done)
169 (dolist (super (sb-mop:class-direct-superclasses class))
170 (push class (gethash super subs))
171 (walk-up super))
172 (setf (gethash class done) t))))
173 (dolist (class classes)
174 (walk-up class))))
175 (labels ((walk-down (this super depth)
176 (format t "~v,0T~A~@[ [~{~A~^ ~}]~]~%"
177 (* 2 depth)
178 (pretty-symbol-name (class-name this) package)
179 (mapcar (lambda (class)
180 (pretty-symbol-name (class-name class)
181 package))
182 (remove super
183 (sb-mop:class-direct-superclasses this))))
7a35400d
MW
184 (dolist (sub (sort (copy-list (gethash this subs))
185 #'string< :key #'class-name))
097d5a3e
MW
186 (walk-down sub this (1+ depth)))))
187 (walk-down (find-class t) nil 0))))
188
189(defun report-symbols (paths package)
190 (setf package (find-package package))
191 (format t "~A~%Package `~(~A~)'~2%"
192 (make-string 77 :initial-element #\-)
193 (package-name package))
194 (dolist (assoc (categorize-symbols paths package))
195 (when (cdr assoc)
196 (format t "~A~%" (file-namestring (car assoc)))
197 (dolist (def (cdr assoc))
198 (let ((sym (car def)))
199 (format t " ~A~@[~48T~{~(~A~)~^ ~}~]~%"
200 (pretty-symbol-name sym package)
201 (cdr def))))
202 (terpri)))
203 (analyse-classes package)
204 (terpri))
205
206(defun report-project-symbols ()
207 (labels ((components (comp)
208 (slot-value comp 'asdf::components))
209 (files (comp)
7a35400d 210 (sort (remove-if-not (lambda (comp)
097d5a3e 211 (typep comp 'asdf:cl-source-file))
7a35400d
MW
212 (components comp))
213 #'string< :key #'asdf:component-name))
097d5a3e
MW
214 (by-name (comp name)
215 (find name (components comp)
216 :test #'string= :key #'asdf:component-name))
217 (file-name (file)
218 (slot-value file 'asdf::absolute-pathname)))
219 (let* ((sod (asdf:find-system "sod"))
220 (parser-files (files (by-name sod "parser")))
221 (utilities (by-name sod "utilities"))
222 (sod-files (remove utilities (files sod))))
223 (report-symbols (mapcar #'file-name sod-files) "SOD")
224 (report-symbols (mapcar #'file-name parser-files) "SOD-PARSER")
225 (report-symbols (mapcar #'file-name (list utilities)) "SOD-UTILITIES"))))