chiark / gitweb /
Lots more has happened.
[sod] / class-output.lisp
CommitLineData
1f1d88f5
MW
1;;; -*-lisp-*-
2;;;
3;;; Output functions for classes
4;;;
5;;; (c) 2009 Straylight/Edgeware
6;;;
7
8;;;----- Licensing notice ---------------------------------------------------
9;;;
10;;; This file is part of the Simple Object Definition system.
11;;;
12;;; SOD is free software; you can redistribute it and/or modify
13;;; it under the terms of the GNU General Public License as published by
14;;; the Free Software Foundation; either version 2 of the License, or
15;;; (at your option) any later version.
16;;;
17;;; SOD is distributed in the hope that it will be useful,
18;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
19;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20;;; GNU General Public License for more details.
21;;;
22;;; You should have received a copy of the GNU General Public License
23;;; along with SOD; if not, write to the Free Software Foundation,
24;;; Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25
26(cl:in-package #:sod)
27
28;;;--------------------------------------------------------------------------
29;;; Utility macro.
30
31(defmacro sequence-output
32 ((streamvar sequencer) &body clauses)
33 (let ((seqvar (gensym "SEQ")))
34 (labels ((convert-item-name (name)
35 (if (listp name)
36 (cons 'list name)
37 name))
38 (convert-constraint (constraint)
39 (cons 'list (mapcar #'convert-item-name constraint)))
40 (process-body (clauses)
41 (if (eq (car clauses) :constraint)
42 (cons `(add-sequencer-constraint
43 ,seqvar
44 ,(convert-constraint (cadr clauses)))
45 (process-body (cddr clauses)))
46 (mapcar (lambda (clause)
47 (let ((name (car clause))
48 (body (cdr clause)))
49 `(add-sequencer-item-function
50 ,seqvar
51 ,(convert-item-name name)
52 (lambda (,streamvar)
53 ,@body))))
54 clauses))))
55 `(let ((,seqvar ,sequencer))
56 ,@(process-body clauses)))))
57
58;;;--------------------------------------------------------------------------
59;;; Classes.
60
61(defmethod add-output-hooks progn
62 ((class sod-class) (reason (eql :h)) sequencer)
63
64 ;; Main output sequencing.
65 (sequence-output (stream sequencer)
66
67 :constraint
68 (:typedefs)
69
70 :constraint
71 ((:classes :start)
72 (class :banner)
73 (class :islots :start) (class :islots :slots) (class :islots :end)
74 (class :vtmsgs :start) (class :vtmsgs :end)
75 (class :vtables :start) (class :vtables :end)
76 (class :vtable-externs) (class :vtable-externs-after)
ddee4bb1 77 (class :methods :start) (class :methods) (class :methods :end)
1f1d88f5
MW
78 (class :ichains :start) (class :ichains :end)
79 (class :ilayout :start) (class :ilayout :slots) (class :ilayout :end)
80 (class :conversions)
ddee4bb1 81 (class :object)
1f1d88f5
MW
82 (:classes :end))
83
84 (:typedefs
85 (format stream "typedef struct ~A ~A;~%"
86 (ichain-struct-tag class (sod-class-chain-head class)) class))
87
88 ((class :banner)
89 (banner (format nil "Class ~A" class) stream))
90 ((class :vtable-externs-after)
ddee4bb1
MW
91 (terpri stream))
92
93 ((class :vtable-externs)
94 (format stream "/* Vtable structures. */~%"))
95
96 ((class :object)
97 (let ((metaclass (sod-class-metaclass class))
98 (metaroot (find-root-metaclass class)))
99 (format stream "/* The class object. */~%~
100 extern struct ~A ~A__classobj;~%~
101 #define ~:*~A__class (&~:*~A__classobj.~A.~A)~2%"
102 (ilayout-struct-tag metaclass) class
103 (sod-class-nickname (sod-class-chain-head metaroot))
104 (sod-class-nickname metaroot)))))
1f1d88f5
MW
105
106 ;; Maybe generate an islots structure.
107 (when (sod-class-slots class)
108 (dolist (slot (sod-class-slots class))
109 (add-output-hooks slot 'populate-islots sequencer))
110 (sequence-output (stream sequencer)
111 ((class :islots :start)
ddee4bb1
MW
112 (format stream "/* Instance slots. */~%~
113 struct ~A {~%"
114 (islots-struct-tag class)))
1f1d88f5
MW
115 ((class :islots :end)
116 (format stream "};~2%"))))
117
118 ;; Declare the direct methods.
119 (when (sod-class-methods class)
1f1d88f5 120 (sequence-output (stream sequencer)
ddee4bb1
MW
121 ((class :methods :start)
122 (format stream "/* Direct methods. */~%"))
123 ((class :methods :end)
1f1d88f5
MW
124 (terpri stream))))
125
126 ;; Provide upcast macros which do the right thing.
127 (when (sod-class-direct-superclasses class)
128 (sequence-output (stream sequencer)
129 ((class :conversions)
130 (let ((chain-head (sod-class-chain-head class)))
ddee4bb1 131 (format stream "/* Conversion macros. */~%")
1f1d88f5
MW
132 (dolist (super (cdr (sod-class-precedence-list class)))
133 (let ((super-head (sod-class-chain-head super)))
ddee4bb1
MW
134 (format stream "#define ~:@(~A__CONV_~A~)(p) ((~A *)~
135 ~:[SOD_XCHAIN(~A, (p))~;(p)~])~%"
1f1d88f5
MW
136 class (sod-class-nickname super) super
137 (eq chain-head super-head)
ddee4bb1
MW
138 (sod-class-nickname super-head))))
139 (terpri stream)))))
1f1d88f5
MW
140
141 ;; Generate vtmsgs structure for all superclasses.
142 (add-output-hooks (car (sod-class-vtables class))
143 'populate-vtmsgs
144 sequencer))
145
146(defmethod add-output-hooks progn ((class sod-class) reason sequencer)
ddee4bb1 147 (with-slots (ilayout vtables methods) class
1f1d88f5 148 (add-output-hooks ilayout reason sequencer)
ddee4bb1 149 (dolist (method methods) (add-output-hooks method reason sequencer))
1f1d88f5
MW
150 (dolist (vtable vtables) (add-output-hooks vtable reason sequencer))))
151
152;;;--------------------------------------------------------------------------
153;;; Instance structure.
154
155(defmethod add-output-hooks progn
156 ((slot sod-slot) (reason (eql 'populate-islots)) sequencer)
157 (sequence-output (stream sequencer)
158 (((sod-slot-class slot) :islots :slots)
159 (pprint-logical-block (stream nil :prefix " " :suffix ";")
160 (pprint-c-type (sod-slot-type slot) stream (sod-slot-name slot)))
161 (terpri stream))))
162
163(defmethod add-output-hooks progn ((ilayout ilayout) reason sequencer)
164 (with-slots (ichains) ilayout
165 (dolist (ichain ichains) (add-output-hooks ichain reason sequencer))))
166
167(defmethod add-output-hooks progn
168 ((ilayout ilayout) (reason (eql :h)) sequencer)
169 (with-slots (class ichains) ilayout
170 (sequence-output (stream sequencer)
171 ((class :ilayout :start)
ddee4bb1
MW
172 (format stream "/* Instance layout. */~%~
173 struct ~A {~%"
174 (ilayout-struct-tag class)))
1f1d88f5
MW
175 ((class :ilayout :end)
176 (format stream "};~2%")))
177 (dolist (ichain ichains)
178 (add-output-hooks ichain 'populate-ilayout sequencer))))
179
180(defmethod add-output-hooks progn
181 ((ichain ichain) (reason (eql :h)) sequencer)
ddee4bb1
MW
182 (with-slots (class chain-head chain-tail) ichain
183 (when (eq class chain-tail)
184 (sequence-output (stream sequencer)
185 :constraint ((class :ichains :start)
186 (class :ichain chain-head :start)
187 (class :ichain chain-head :slots)
188 (class :ichain chain-head :end)
189 (class :ichains :end))
190 ((class :ichain chain-head :start)
191 (format stream "/* Instance chain structure. */~%~
192 struct ~A {~%"
193 (ichain-struct-tag chain-tail chain-head)))
194 ((class :ichain chain-head :end)
195 (format stream "};~2%")
196 (format stream "/* Union of equivalent superclass chains. */~%~
197 union ~A {~%~
198 ~:{ struct ~A ~A;~%~}~
199 };~2%"
200 (ichain-union-tag chain-tail chain-head)
201 (mapcar (lambda (super)
202 (list (ichain-struct-tag super chain-head)
203 (sod-class-nickname super)))
204 (sod-class-chain chain-tail))))))))
1f1d88f5
MW
205
206(defmethod add-output-hooks progn
207 ((ichain ichain) (reason (eql 'populate-ilayout)) sequencer)
ddee4bb1 208 (with-slots (class chain-head chain-tail) ichain
1f1d88f5
MW
209 (sequence-output (stream sequencer)
210 ((class :ilayout :slots)
ddee4bb1
MW
211 (format stream " union ~A ~A;~%"
212 (ichain-union-tag chain-tail chain-head)
1f1d88f5
MW
213 (sod-class-nickname chain-head))))))
214
1f1d88f5
MW
215(defmethod add-output-hooks progn
216 ((vtptr vtable-pointer) (reason (eql :h)) sequencer)
ddee4bb1 217 (with-slots (class chain-head chain-tail) vtptr
1f1d88f5
MW
218 (sequence-output (stream sequencer)
219 ((class :ichain chain-head :slots)
220 (format stream " const struct ~A *_vt;~%"
ddee4bb1 221 (vtable-struct-tag chain-tail chain-head))))))
1f1d88f5
MW
222
223(defmethod add-output-hooks progn
224 ((islots islots) (reason (eql :h)) sequencer)
225 (with-slots (class subclass slots) islots
226 (sequence-output (stream sequencer)
227 ((subclass :ichain (sod-class-chain-head class) :slots)
228 (format stream " struct ~A ~A;~%"
229 (islots-struct-tag class)
230 (sod-class-nickname class))))))
231
232;;;--------------------------------------------------------------------------
233;;; Vtable structure.
234
235(defmethod add-output-hooks progn ((vtable vtable) reason sequencer)
236 (with-slots (body) vtable
237 (dolist (item body) (add-output-hooks item reason sequencer))))
238
ddee4bb1
MW
239(defmethod add-output-hooks progn
240 ((method sod-method) (reason (eql :h)) sequencer)
241 (with-slots (class) method
242 (sequence-output (stream sequencer)
243 ((class :methods)
244 (let ((type (sod-method-function-type method)))
245 (princ "extern " stream)
246 (pprint-c-type (commentify-function-type type) stream
247 (sod-method-function-name method))
248 (format stream ";~%"))))))
249
1f1d88f5
MW
250(defmethod add-output-hooks progn
251 ((vtable vtable) (reason (eql :h)) sequencer)
ddee4bb1
MW
252 (with-slots (class chain-head chain-tail) vtable
253 (when (eq class chain-tail)
254 (sequence-output (stream sequencer)
255 :constraint ((class :vtables :start)
256 (class :vtable chain-head :start)
257 (class :vtable chain-head :slots)
258 (class :vtable chain-head :end)
259 (class :vtables :end))
260 ((class :vtable chain-head :start)
261 (format stream "/* Vtable structure. */~%~
262 struct ~A {~%"
263 (vtable-struct-tag chain-tail chain-head)))
264 ((class :vtable chain-head :end)
265 (format stream "};~2%"))))
1f1d88f5 266 (sequence-output (stream sequencer)
1f1d88f5
MW
267 ((class :vtable-externs)
268 (format stream "~@<extern struct ~A ~2I~_~A__vtable_~A;~:>~%"
ddee4bb1 269 (vtable-struct-tag chain-tail chain-head)
1f1d88f5
MW
270 class (sod-class-nickname chain-head))))))
271
272(defmethod add-output-hooks progn
273 ((vtmsgs vtmsgs) (reason (eql :h)) sequencer)
ddee4bb1 274 (with-slots (class subclass chain-head chain-tail) vtmsgs
1f1d88f5
MW
275 (sequence-output (stream sequencer)
276 ((subclass :vtable chain-head :slots)
277 (format stream " struct ~A ~A;~%"
278 (vtmsgs-struct-tag subclass class)
279 (sod-class-nickname class))))))
280
281(defmethod add-output-hooks progn
282 ((vtmsgs vtmsgs) (reason (eql 'populate-vtmsgs)) sequencer)
283 (when (vtmsgs-entries vtmsgs)
284 (with-slots (class subclass) vtmsgs
285 (sequence-output (stream sequencer)
286 :constraint ((subclass :vtmsgs :start)
287 (subclass :vtmsgs class :start)
288 (subclass :vtmsgs class :slots)
289 (subclass :vtmsgs class :end)
290 (subclass :vtmsgs :end))
291 ((subclass :vtmsgs class :start)
ddee4bb1
MW
292 (format stream "/* Messages protocol from class ~A */~%~
293 struct ~A {~%"
294 class
295 (vtmsgs-struct-tag subclass class)))
1f1d88f5
MW
296 ((subclass :vtmsgs class :end)
297 (format stream "};~2%"))))))
298
299(defmethod add-output-hooks progn ((vtmsgs vtmsgs) reason sequencer)
300 (with-slots (entries) vtmsgs
301 (dolist (entry entries) (add-output-hooks entry reason sequencer))))
302
303(defmethod add-output-hooks progn ((entry method-entry) reason sequencer)
304 (with-slots (method) entry
305 (add-output-hooks method reason sequencer)))
306
307(defmethod add-output-hooks progn
ddee4bb1
MW
308 ((entry method-entry) (reason (eql 'populate-vtmsgs)) sequencer)
309 (let* ((method (method-entry-effective-method entry))
310 (message (effective-method-message method))
1f1d88f5 311 (class (effective-method-class method))
ddee4bb1
MW
312 (type (method-entry-function-type entry))
313 (commented-type (commentify-function-type type)))
1f1d88f5
MW
314 (sequence-output (stream sequencer)
315 ((class :vtmsgs (sod-message-class message) :slots)
316 (pprint-logical-block (stream nil :prefix " " :suffix ";")
ddee4bb1 317 (pprint-c-type commented-type stream (sod-message-name message)))
1f1d88f5
MW
318 (terpri stream)))))
319
320(defmethod add-output-hooks progn
321 ((cptr class-pointer) (reason (eql :h)) sequencer)
322 (with-slots (class chain-head metaclass meta-chain-head) cptr
323 (sequence-output (stream sequencer)
324 ((class :vtable chain-head :slots)
325 (format stream " const ~A *~:[_class~;~:*_cls_~A~];~%"
326 metaclass
327 (if (sod-class-direct-superclasses meta-chain-head)
328 (sod-class-nickname meta-chain-head)
329 nil))))))
330
331(defmethod add-output-hooks progn
332 ((boff base-offset) (reason (eql :h)) sequencer)
333 (with-slots (class chain-head) boff
334 (sequence-output (stream sequencer)
335 ((class :vtable chain-head :slots)
336 (write-line " size_t _base;" stream)))))
337
338(defmethod add-output-hooks progn
339 ((choff chain-offset) (reason (eql :h)) sequencer)
340 (with-slots (class chain-head target-head) choff
341 (sequence-output (stream sequencer)
342 ((class :vtable chain-head :slots)
343 (format stream " ptrdiff_t _off_~A;~%"
344 (sod-class-nickname target-head))))))
345
346;;;--------------------------------------------------------------------------
347;;; Testing.
348
349#+test
350(defun test (name)
351 (let ((sequencer (make-instance 'sequencer))
352 (class (find-sod-class name)))
353 (add-output-hooks class :h sequencer)
354 (invoke-sequencer-items sequencer *standard-output*)
355 sequencer))
356
357;;;----- That's all, folks --------------------------------------------------