src/class-output.lisp: Replace `Classes' with a more helpful title.
[sod] / src / class-output.lisp
CommitLineData
1f1d88f5
MW
1;;; -*-lisp-*-
2;;;
dea4d055 3;;; Output for classes
1f1d88f5
MW
4;;;
5;;; (c) 2009 Straylight/Edgeware
6;;;
7
8;;;----- Licensing notice ---------------------------------------------------
9;;;
e0808c47 10;;; This file is part of the Sensible Object Design, an object system for C.
1f1d88f5
MW
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;;;--------------------------------------------------------------------------
6e2d4b52
MW
29;;; Walking the layout tree.
30
7d8d3a16 31(defmethod hook-output :after ((class sod-class) reason sequencer)
6e2d4b52
MW
32 (with-slots ((ilayout %ilayout) vtables methods effective-methods) class
33 (hook-output ilayout reason sequencer)
34 (dolist (method methods) (hook-output method reason sequencer))
35 (dolist (method effective-methods) (hook-output method reason sequencer))
36 (dolist (vtable vtables) (hook-output vtable reason sequencer))))
37
7d8d3a16 38(defmethod hook-output :after ((ilayout ilayout) reason sequencer)
6e2d4b52
MW
39 (with-slots (ichains) ilayout
40 (dolist (ichain ichains) (hook-output ichain reason sequencer))))
41
7d8d3a16 42(defmethod hook-output :after ((ichain ichain) reason sequencer)
1224dfb0 43 (dolist (item (ichain-body ichain)) (hook-output item reason sequencer)))
6e2d4b52 44
7d8d3a16 45(defmethod hook-output :after ((islots islots) reason sequencer)
1224dfb0 46 (dolist (slot (islots-slots islots)) (hook-output slot reason sequencer)))
6e2d4b52 47
7d8d3a16 48(defmethod hook-output :after ((vtable vtable) reason sequencer)
6e2d4b52
MW
49 (with-slots (body) vtable
50 (dolist (item body) (hook-output item reason sequencer))))
51
7d8d3a16 52(defmethod hook-output :after ((vtmsgs vtmsgs) reason sequencer)
6e2d4b52
MW
53 (with-slots (entries) vtmsgs
54 (dolist (entry entries) (hook-output entry reason sequencer))))
55
56;;;--------------------------------------------------------------------------
6e409901 57;;; Class declarations.
1f1d88f5 58
7d8d3a16 59(defmethod hook-output ((class sod-class) (reason (eql :h)) sequencer)
1f1d88f5
MW
60
61 ;; Main output sequencing.
62 (sequence-output (stream sequencer)
63
64 :constraint
1f1d88f5
MW
65 ((:classes :start)
66 (class :banner)
67 (class :islots :start) (class :islots :slots) (class :islots :end)
68 (class :vtmsgs :start) (class :vtmsgs :end)
69 (class :vtables :start) (class :vtables :end)
70 (class :vtable-externs) (class :vtable-externs-after)
43073476
MW
71 (class :methods :start) (class :methods :defs)
72 (class :methods) (class :methods :end)
1f1d88f5
MW
73 (class :ichains :start) (class :ichains :end)
74 (class :ilayout :start) (class :ilayout :slots) (class :ilayout :end)
75 (class :conversions)
6bc944c3 76 (class :message-macros)
ddee4bb1 77 (class :object)
1f1d88f5
MW
78 (:classes :end))
79
80 (:typedefs
81 (format stream "typedef struct ~A ~A;~%"
82 (ichain-struct-tag class (sod-class-chain-head class)) class))
83
84 ((class :banner)
85 (banner (format nil "Class ~A" class) stream))
86 ((class :vtable-externs-after)
ddee4bb1
MW
87 (terpri stream))
88
89 ((class :vtable-externs)
90 (format stream "/* Vtable structures. */~%"))
91
92 ((class :object)
93 (let ((metaclass (sod-class-metaclass class))
94 (metaroot (find-root-metaclass class)))
a07d8d00
MW
95 (format stream "/* The class object. */~@
96 extern const struct ~A ~A__classobj;~@
489173a5 97 #define ~:*~A__class (&~:*~A__classobj.~A.~A)~%"
ddee4bb1
MW
98 (ilayout-struct-tag metaclass) class
99 (sod-class-nickname (sod-class-chain-head metaroot))
489173a5
MW
100 (sod-class-nickname metaroot))
101 (dolist (chain (sod-class-chains metaclass))
102 (let ((tail (car chain)))
103 (unless (eq tail metaroot)
104 (format stream "#define ~A__cls_~A (&~2:*~A__classobj.~A.~A)~%"
105 class (sod-class-nickname (sod-class-chain-head tail))
106 (sod-class-nickname tail)))))
107 (terpri stream))))
1f1d88f5
MW
108
109 ;; Maybe generate an islots structure.
110 (when (sod-class-slots class)
1f1d88f5
MW
111 (sequence-output (stream sequencer)
112 ((class :islots :start)
a07d8d00 113 (format stream "/* Instance slots. */~@
ddee4bb1
MW
114 struct ~A {~%"
115 (islots-struct-tag class)))
1f1d88f5
MW
116 ((class :islots :end)
117 (format stream "};~2%"))))
118
119 ;; Declare the direct methods.
120 (when (sod-class-methods class)
1f1d88f5 121 (sequence-output (stream sequencer)
ddee4bb1
MW
122 ((class :methods :start)
123 (format stream "/* Direct methods. */~%"))
124 ((class :methods :end)
1f1d88f5
MW
125 (terpri stream))))
126
127 ;; Provide upcast macros which do the right thing.
128 (when (sod-class-direct-superclasses class)
129 (sequence-output (stream sequencer)
130 ((class :conversions)
131 (let ((chain-head (sod-class-chain-head class)))
ddee4bb1 132 (format stream "/* Conversion macros. */~%")
1f1d88f5
MW
133 (dolist (super (cdr (sod-class-precedence-list class)))
134 (let ((super-head (sod-class-chain-head super)))
bb172d53
MW
135 (format stream "#define ~:@(~A__CONV_~A~)(_obj) ((~A *)~
136 ~:[SOD_XCHAIN(~A, (_obj))~;(_obj)~])~%"
1f1d88f5
MW
137 class (sod-class-nickname super) super
138 (eq chain-head super-head)
ddee4bb1
MW
139 (sod-class-nickname super-head))))
140 (terpri stream)))))
1f1d88f5 141
6bc944c3
MW
142 ;; Provide convenience macros for sending the newly defined messages. (The
143 ;; macros work on all subclasses too.)
144 ;;
145 ;; We need each message's method entry type for this, so we need to dig it
146 ;; out of the vtmsgs structure. Indeed, the vtmsgs for this class contains
147 ;; entries for precisely the messages we want to make macros for.
43073476
MW
148 (when (some (lambda (message)
149 (or (keyword-message-p message)
150 (varargs-message-p message)))
151 (sod-class-messages class))
e674612e
MW
152 (one-off-output 'varargs-macros sequencer :early-decls
153 (lambda (stream)
154 (format stream
155 "~%SOD__VARARGS_MACROS_PREAMBLE~%"))))
6bc944c3
MW
156 (when (sod-class-messages class)
157 (sequence-output (stream sequencer)
158 ((class :message-macros)
159 (let* ((vtable (find (sod-class-chain-head class)
160 (sod-class-vtables class)
161 :key #'vtable-chain-head))
162 (vtmsgs (find-if (lambda (item)
163 (and (typep item 'vtmsgs)
164 (eql (vtmsgs-class item) class)))
165 (vtable-body vtable))))
166 (format stream "/* Message invocation macros. */~%")
6bc944c3
MW
167 (dolist (entry (vtmsgs-entries vtmsgs))
168 (let* ((type (method-entry-function-type entry))
169 (args (c-function-arguments type))
6bc944c3
MW
170 (in-names nil) (out-names nil) (varargsp nil) (me "me"))
171 (do ((args args (cdr args)))
172 ((endp args))
b426ab51 173 (let* ((raw-name (princ-to-string (argument-name (car args))))
6bc944c3
MW
174 (name (if (find raw-name
175 (list "_vt"
176 (sod-class-nickname class)
b426ab51 177 (method-entry-slot-name entry))
6bc944c3
MW
178 :test #'string=)
179 (format nil "sod__a_~A" raw-name)
180 raw-name)))
181 (cond ((and (cdr args) (eq (cadr args) :ellipsis))
182 (setf varargsp t)
68a4f8c9 183 (unless in-names (setf me "SOD__CAR(__VA_ARGS__)"))
6bc944c3
MW
184 (push (format nil "/*~A*/ ..." name) in-names)
185 (push "__VA_ARGS__" out-names)
186 (return))
187 (t
188 (push name in-names)
189 (push name out-names)))))
190 (when varargsp
e674612e 191 (format stream "#ifdef SOD__HAVE_VARARGS_MACROS~%"))
6bc944c3 192 (format stream "#define ~A(~{~A~^, ~}) ~
d908a89e 193 (~A)->_vt->~A.~A(~{~A~^, ~})~%"
b426ab51 194 (message-macro-name class entry)
6bc944c3
MW
195 (nreverse in-names)
196 me
197 (sod-class-nickname class)
b426ab51 198 (method-entry-slot-name entry)
6bc944c3
MW
199 (nreverse out-names))
200 (when varargsp
201 (format stream "#endif~%"))))
7d8d3a16
MW
202 (terpri stream))))))
203
204(defmethod hook-output :after ((class sod-class) (reason (eql :h)) sequencer)
6bc944c3 205
7d8d3a16
MW
206 ;; Output a structure member definition for each instance slot.
207 (dolist (slot (sod-class-slots class))
208 (hook-output slot 'islots sequencer))
209
210 ;; Generate a vtmsgs structure for all superclasses.
6e2d4b52 211 (hook-output (car (sod-class-vtables class)) 'vtmsgs sequencer))
1f1d88f5
MW
212
213;;;--------------------------------------------------------------------------
214;;; Instance structure.
215
7d8d3a16 216(defmethod hook-output ((slot sod-slot) (reason (eql 'islots)) sequencer)
1f1d88f5
MW
217 (sequence-output (stream sequencer)
218 (((sod-slot-class slot) :islots :slots)
219 (pprint-logical-block (stream nil :prefix " " :suffix ";")
220 (pprint-c-type (sod-slot-type slot) stream (sod-slot-name slot)))
221 (terpri stream))))
222
7d8d3a16
MW
223(defmethod hook-output ((ilayout ilayout) (reason (eql :h)) sequencer)
224 (with-slots ((class %class)) ilayout
1f1d88f5
MW
225 (sequence-output (stream sequencer)
226 ((class :ilayout :start)
a07d8d00 227 (format stream "/* Instance layout. */~@
ddee4bb1
MW
228 struct ~A {~%"
229 (ilayout-struct-tag class)))
1f1d88f5 230 ((class :ilayout :end)
7d8d3a16
MW
231 (format stream "};~2%")))))
232
233(defmethod hook-output :after ((ilayout ilayout) (reason (eql :h)) sequencer)
234 (dolist (ichain (ilayout-ichains ilayout))
235 (hook-output ichain 'ilayout sequencer)))
1f1d88f5 236
7d8d3a16 237(defmethod hook-output ((ichain ichain) (reason (eql :h)) sequencer)
4b8e5c03 238 (with-slots ((class %class) chain-head chain-tail) ichain
ddee4bb1
MW
239 (when (eq class chain-tail)
240 (sequence-output (stream sequencer)
241 :constraint ((class :ichains :start)
242 (class :ichain chain-head :start)
243 (class :ichain chain-head :slots)
244 (class :ichain chain-head :end)
245 (class :ichains :end))
246 ((class :ichain chain-head :start)
a07d8d00 247 (format stream "/* Instance chain structure. */~@
ddee4bb1
MW
248 struct ~A {~%"
249 (ichain-struct-tag chain-tail chain-head)))
250 ((class :ichain chain-head :end)
251 (format stream "};~2%")
a07d8d00
MW
252 (format stream "/* Union of equivalent superclass chains. */~@
253 union ~A {~@
ddee4bb1
MW
254 ~:{ struct ~A ~A;~%~}~
255 };~2%"
256 (ichain-union-tag chain-tail chain-head)
dea4d055
MW
257
258 ;; Make sure the most specific class is first: only the
259 ;; first element of a union can be statically initialized in
260 ;; C90.
ddee4bb1
MW
261 (mapcar (lambda (super)
262 (list (ichain-struct-tag super chain-head)
263 (sod-class-nickname super)))
264 (sod-class-chain chain-tail))))))))
1f1d88f5 265
7d8d3a16 266(defmethod hook-output ((ichain ichain) (reason (eql 'ilayout)) sequencer)
4b8e5c03 267 (with-slots ((class %class) chain-head chain-tail) ichain
1f1d88f5
MW
268 (sequence-output (stream sequencer)
269 ((class :ilayout :slots)
ddee4bb1
MW
270 (format stream " union ~A ~A;~%"
271 (ichain-union-tag chain-tail chain-head)
1f1d88f5
MW
272 (sod-class-nickname chain-head))))))
273
7d8d3a16 274(defmethod hook-output ((vtptr vtable-pointer) (reason (eql :h)) sequencer)
4b8e5c03 275 (with-slots ((class %class) chain-head chain-tail) vtptr
64fd357d
MW
276 (when (eq class chain-tail)
277 (sequence-output (stream sequencer)
278 ((class :ichain chain-head :slots)
279 (format stream " const struct ~A *_vt;~%"
280 (vtable-struct-tag chain-tail chain-head)))))))
1f1d88f5 281
7d8d3a16 282(defmethod hook-output ((islots islots) (reason (eql :h)) sequencer)
4b8e5c03 283 (with-slots ((class %class) subclass slots) islots
64fd357d
MW
284 (let ((head (sod-class-chain-head class)))
285 (when (eq head (sod-class-chain-head subclass))
286 (sequence-output (stream sequencer)
287 ((subclass :ichain (sod-class-chain-head class) :slots)
288 (format stream " struct ~A ~A;~%"
289 (islots-struct-tag class)
290 (sod-class-nickname class))))))))
1f1d88f5
MW
291
292;;;--------------------------------------------------------------------------
293;;; Vtable structure.
294
7d8d3a16 295(defmethod hook-output ((method sod-method) (reason (eql :h)) sequencer)
4b8e5c03 296 (with-slots ((class %class)) method
ddee4bb1
MW
297 (sequence-output (stream sequencer)
298 ((class :methods)
299 (let ((type (sod-method-function-type method)))
300 (princ "extern " stream)
301 (pprint-c-type (commentify-function-type type) stream
302 (sod-method-function-name method))
43073476
MW
303 (format stream ";~%")))
304 ((class :methods :defs)
305 (let* ((type (sod-method-type method))
306 (keys (and (typep type 'c-keyword-function-type)
307 (c-function-keywords type))))
308 (when keys
309 (format stream "struct ~A {~%~
fd040f06 310 ~{ unsigned ~A: 1;~%~}~
43073476
MW
311 };~2%"
312 (direct-method-suppliedp-struct-tag method)
313 (mapcar #'argument-name keys))))))))
ddee4bb1 314
7d8d3a16 315(defmethod hook-output ((vtable vtable) (reason (eql :h)) sequencer)
4b8e5c03 316 (with-slots ((class %class) chain-head chain-tail) vtable
ddee4bb1
MW
317 (when (eq class chain-tail)
318 (sequence-output (stream sequencer)
319 :constraint ((class :vtables :start)
320 (class :vtable chain-head :start)
321 (class :vtable chain-head :slots)
322 (class :vtable chain-head :end)
323 (class :vtables :end))
324 ((class :vtable chain-head :start)
a07d8d00 325 (format stream "/* Vtable structure. */~@
ddee4bb1
MW
326 struct ~A {~%"
327 (vtable-struct-tag chain-tail chain-head)))
328 ((class :vtable chain-head :end)
c2438e62
MW
329 (format stream "};~2%")
330 (format stream "/* Union of equivalent superclass vtables. */~@
331 union ~A {~@
332 ~:{ struct ~A ~A;~%~}~
333 };~2%"
334 (vtable-union-tag chain-tail chain-head)
335
336 ;; As for the ichain union, make sure the most specific
337 ;; class is first.
338 (mapcar (lambda (super)
339 (list (vtable-struct-tag super chain-head)
340 (sod-class-nickname super)))
341 (sod-class-chain chain-tail))))))
1f1d88f5 342 (sequence-output (stream sequencer)
1f1d88f5 343 ((class :vtable-externs)
7c3bae74 344 (format stream "~@<extern const union ~A ~2I~_~A;~:>~%"
c2438e62 345 (vtable-union-tag chain-tail chain-head)
7c3bae74 346 (vtable-name class chain-head))))))
1f1d88f5 347
7d8d3a16 348(defmethod hook-output ((vtmsgs vtmsgs) (reason (eql :h)) sequencer)
4b8e5c03 349 (with-slots ((class %class) subclass chain-head chain-tail) vtmsgs
64fd357d
MW
350 (when (eq subclass chain-tail)
351 (sequence-output (stream sequencer)
352 ((subclass :vtable chain-head :slots)
353 (format stream " struct ~A ~A;~%"
354 (vtmsgs-struct-tag subclass class)
355 (sod-class-nickname class)))))))
1f1d88f5 356
7d8d3a16 357(defmethod hook-output ((vtmsgs vtmsgs) (reason (eql 'vtmsgs)) sequencer)
1f1d88f5 358 (when (vtmsgs-entries vtmsgs)
4b8e5c03 359 (with-slots ((class %class) subclass) vtmsgs
1f1d88f5
MW
360 (sequence-output (stream sequencer)
361 :constraint ((subclass :vtmsgs :start)
362 (subclass :vtmsgs class :start)
363 (subclass :vtmsgs class :slots)
364 (subclass :vtmsgs class :end)
365 (subclass :vtmsgs :end))
366 ((subclass :vtmsgs class :start)
a07d8d00 367 (format stream "/* Messages protocol from class ~A */~@
ddee4bb1
MW
368 struct ~A {~%"
369 class
370 (vtmsgs-struct-tag subclass class)))
1f1d88f5
MW
371 ((subclass :vtmsgs class :end)
372 (format stream "};~2%"))))))
373
7d8d3a16
MW
374(defmethod hook-output ((entry method-entry)
375 (reason (eql 'vtmsgs)) sequencer)
ddee4bb1
MW
376 (let* ((method (method-entry-effective-method entry))
377 (message (effective-method-message method))
1f1d88f5 378 (class (effective-method-class method))
9ec578d9
MW
379 (function-type (method-entry-function-type entry))
380 (commented-type (commentify-function-type function-type))
381 (pointer-type (make-pointer-type commented-type)))
1f1d88f5
MW
382 (sequence-output (stream sequencer)
383 ((class :vtmsgs (sod-message-class message) :slots)
384 (pprint-logical-block (stream nil :prefix " " :suffix ";")
b426ab51 385 (pprint-c-type pointer-type stream (method-entry-slot-name entry)))
1f1d88f5
MW
386 (terpri stream)))))
387
7d8d3a16 388(defmethod hook-output ((cptr class-pointer) (reason (eql :h)) sequencer)
4b8e5c03 389 (with-slots ((class %class) chain-head metaclass meta-chain-head) cptr
64fd357d
MW
390 (when (eq chain-head (sod-class-chain-head class))
391 (sequence-output (stream sequencer)
392 ((class :vtable chain-head :slots)
393 (format stream " const ~A *~:[_class~;~:*_cls_~A~];~%"
394 metaclass
395 (and (sod-class-direct-superclasses meta-chain-head)
396 (sod-class-nickname meta-chain-head))))))))
1f1d88f5 397
7d8d3a16 398(defmethod hook-output ((boff base-offset) (reason (eql :h)) sequencer)
4b8e5c03 399 (with-slots ((class %class) chain-head) boff
64fd357d
MW
400 (when (eq chain-head (sod-class-chain-head class))
401 (sequence-output (stream sequencer)
402 ((class :vtable chain-head :slots)
403 (write-line " size_t _base;" stream))))))
1f1d88f5 404
7d8d3a16 405(defmethod hook-output ((choff chain-offset) (reason (eql :h)) sequencer)
4b8e5c03 406 (with-slots ((class %class) chain-head target-head) choff
64fd357d
MW
407 (when (eq chain-head (sod-class-chain-head class))
408 (sequence-output (stream sequencer)
409 ((class :vtable chain-head :slots)
410 (format stream " ptrdiff_t _off_~A;~%"
411 (sod-class-nickname target-head)))))))
1f1d88f5
MW
412
413;;;--------------------------------------------------------------------------
3be8c2bf
MW
414;;; Implementation output.
415
6e2d4b52 416(export '*instance-class*)
4b856491
MW
417(defvar *instance-class* nil
418 "The class currently being output.
419
420 This is bound during the `hook-output' traversal of a class layout for
421 `:c' output, since some of the objects traversed actually `belong' to
422 superclasses and there's no other way to find out what the reference class
423 actually is.
424
425 It may be bound at other times.")
3be8c2bf 426
7d8d3a16 427(defmethod hook-output ((class sod-class) (reason (eql :c)) sequencer)
3be8c2bf
MW
428 (sequence-output (stream sequencer)
429
430 :constraint
431 ((:classes :start)
432 (class :banner)
433 (class :direct-methods :start) (class :direct-methods :end)
a07d8d00 434 (class :effective-methods)
3be8c2bf
MW
435 (class :vtables :start) (class :vtables :end)
436 (class :object :prepare) (class :object :start) (class :object :end)
437 (:classes :end))
438
439 ((class :banner)
440 (banner (format nil "Class ~A" class) stream))
441
442 ((class :object :start)
443 (format stream "~
444/* The class object. */
445const struct ~A ~A__classobj = {~%"
446 (ilayout-struct-tag (sod-class-metaclass class))
447 class))
448 ((class :object :end)
7d8d3a16 449 (format stream "};~2%"))))
3be8c2bf 450
7d8d3a16 451(defmethod hook-output :after ((class sod-class) (reason (eql :c)) sequencer)
3be8c2bf 452 (let ((*instance-class* class))
dea4d055 453 (hook-output (sod-class-ilayout (sod-class-metaclass class))
6e2d4b52 454 'class sequencer)))
3be8c2bf
MW
455
456;;;--------------------------------------------------------------------------
9ec578d9 457;;; Direct and effective methods.
3be8c2bf 458
7d8d3a16
MW
459(defmethod hook-output ((method delegating-direct-method)
460 (reason (eql :c)) sequencer)
4b8e5c03 461 (with-slots ((class %class) body) method
3be8c2bf 462 (unless body
dea4d055 463 (return-from hook-output))
3be8c2bf
MW
464 (sequence-output (stream sequencer)
465 ((class :direct-method method :start)
466 (format stream "#define CALL_NEXT_METHOD (next_method(~{~A~^, ~}))~%"
467 (mapcar #'argument-name
468 (c-function-arguments (sod-method-next-method-type
469 method)))))
470 ((class :direct-method method :end)
7d8d3a16
MW
471 (format stream "#undef CALL_NEXT_METHOD~%"))))
472 (call-next-method))
3be8c2bf 473
7d8d3a16 474(defmethod hook-output ((method sod-method) (reason (eql :c)) sequencer)
7de8c666 475 (with-slots ((class %class) role body message) method
3be8c2bf 476 (unless body
dea4d055 477 (return-from hook-output))
3be8c2bf
MW
478 (sequence-output (stream sequencer)
479 :constraint ((class :direct-methods :start)
7de8c666 480 (class :direct-method method :banner)
3be8c2bf
MW
481 (class :direct-method method :start)
482 (class :direct-method method :body)
483 (class :direct-method method :end)
484 (class :direct-methods :end))
7de8c666
MW
485 ((class :direct-method method :banner)
486 (format-banner-comment stream "Direct ~@[~(~A~) ~]method ~:_~
487 on `~A.~A' ~:_defined by `~A'."
488 role
489 (sod-class-nickname
490 (sod-message-class message))
491 (sod-message-name message)
492 class)
493 (fresh-line stream))
3be8c2bf
MW
494 ((class :direct-method method :body)
495 (pprint-c-type (sod-method-function-type method)
496 stream
497 (sod-method-function-name method))
498 (format stream "~&{~%")
499 (write body :stream stream :pretty nil :escape nil)
500 (format stream "~&}~%"))
501 ((class :direct-method method :end)
502 (terpri stream)))))
503
7d8d3a16
MW
504(defmethod hook-output ((method basic-effective-method)
505 (reason (eql :c)) sequencer)
4b8e5c03 506 (with-slots ((class %class) functions) method
dea4d055
MW
507 (sequence-output (stream sequencer)
508 ((class :effective-methods)
43073476
MW
509 (let* ((keys (effective-method-keywords method))
510 (message (effective-method-message method))
511 (msg-class (sod-message-class message)))
512 (when keys
513 (format-banner-comment stream "Keyword argument structure ~:_~
514 for `~A.~A' ~:_on class `~A'."
515 (sod-class-nickname msg-class)
516 (sod-message-name message)
517 class)
518 (format stream "~&struct ~A {~%"
519 (effective-method-keyword-struct-tag method))
fd040f06 520 (format stream "~{ unsigned ~A__suppliedp: 1;~%~}"
43073476
MW
521 (mapcar #'argument-name keys))
522 (dolist (key keys)
523 (write-string " " stream)
524 (pprint-c-type (argument-type key) stream (argument-name key))
525 (format stream ";~%"))
526 (format stream "};~2%")))
dea4d055
MW
527 (dolist (func functions)
528 (write func :stream stream :escape nil :circle nil))))))
529
3be8c2bf 530;;;--------------------------------------------------------------------------
a07d8d00
MW
531;;; Vtables.
532
7d8d3a16 533(defmethod hook-output ((vtable vtable) (reason (eql :c)) sequencer)
4b8e5c03 534 (with-slots ((class %class) chain-head chain-tail) vtable
a07d8d00
MW
535 (sequence-output (stream sequencer)
536 :constraint ((class :vtables :start)
537 (class :vtable chain-head :start)
538 (class :vtable chain-head :end)
539 (class :vtables :end))
540 ((class :vtable chain-head :start)
541 (format stream "/* Vtable for ~A chain. */~@
c2438e62 542 const union ~A ~A = { {~%"
a07d8d00 543 chain-head
c2438e62 544 (vtable-union-tag chain-tail chain-head)
9ec578d9 545 (vtable-name class chain-head)))
a07d8d00 546 ((class :vtable chain-head :end)
c2438e62 547 (format stream "} };~2%")))))
a07d8d00 548
7d8d3a16 549(defmethod hook-output ((cptr class-pointer) (reason (eql :c)) sequencer)
4b8e5c03 550 (with-slots ((class %class) chain-head metaclass meta-chain-head) cptr
a07d8d00
MW
551 (sequence-output (stream sequencer)
552 :constraint ((class :vtable chain-head :start)
553 (class :vtable chain-head :class-pointer metaclass)
554 (class :vtable chain-head :end))
555 ((class :vtable chain-head :class-pointer metaclass)
9ec578d9
MW
556 (format stream " /* ~21@A = */ &~A__classobj.~A.~A,~%"
557 (if (sod-class-direct-superclasses meta-chain-head)
558 (format nil "_cls_~A"
559 (sod-class-nickname meta-chain-head))
560 "_class")
fc5d9486 561 class
a07d8d00
MW
562 (sod-class-nickname meta-chain-head)
563 (sod-class-nickname metaclass))))))
564
7d8d3a16 565(defmethod hook-output ((boff base-offset) (reason (eql :c)) sequencer)
4b8e5c03 566 (with-slots ((class %class) chain-head) boff
a07d8d00
MW
567 (sequence-output (stream sequencer)
568 :constraint ((class :vtable chain-head :start)
569 (class :vtable chain-head :base-offset)
570 (class :vtable chain-head :end))
571 ((class :vtable chain-head :base-offset)
9ec578d9
MW
572 (format stream " /* ~21@A = */ offsetof(struct ~A, ~A),~%"
573 "_base"
a07d8d00
MW
574 (ilayout-struct-tag class)
575 (sod-class-nickname chain-head))))))
576
7d8d3a16 577(defmethod hook-output ((choff chain-offset) (reason (eql :c)) sequencer)
4b8e5c03 578 (with-slots ((class %class) chain-head target-head) choff
a07d8d00
MW
579 (sequence-output (stream sequencer)
580 :constraint ((class :vtable chain-head :start)
581 (class :vtable chain-head :chain-offset target-head)
582 (class :vtable chain-head :end))
583 ((class :vtable chain-head :chain-offset target-head)
9ec578d9
MW
584 (format stream " /* ~21@A = */ SOD_OFFSETDIFF(struct ~A, ~A, ~A),~%"
585 (format nil "_off_~A" (sod-class-nickname target-head))
a07d8d00
MW
586 (ilayout-struct-tag class)
587 (sod-class-nickname chain-head)
588 (sod-class-nickname target-head))))))
589
7d8d3a16 590(defmethod hook-output ((vtmsgs vtmsgs) (reason (eql :c)) sequencer)
4b8e5c03 591 (with-slots ((class %class) subclass chain-head) vtmsgs
a07d8d00
MW
592 (sequence-output (stream sequencer)
593 :constraint ((subclass :vtable chain-head :start)
594 (subclass :vtable chain-head :vtmsgs class :start)
595 (subclass :vtable chain-head :vtmsgs class :slots)
596 (subclass :vtable chain-head :vtmsgs class :end)
597 (subclass :vtable chain-head :end))
598 ((subclass :vtable chain-head :vtmsgs class :start)
599 (format stream " { /* Method entries for ~A messages. */~%"
600 class))
601 ((subclass :vtable chain-head :vtmsgs class :end)
602 (format stream " },~%")))))
603
7d8d3a16 604(defmethod hook-output ((entry method-entry) (reason (eql :c)) sequencer)
4b8e5c03 605 (with-slots ((method %method) chain-head chain-tail role) entry
a07d8d00
MW
606 (let* ((message (effective-method-message method))
607 (class (effective-method-class method))
608 (super (sod-message-class message)))
609 (sequence-output (stream sequencer)
610 ((class :vtable chain-head :vtmsgs super :slots)
9ec578d9 611 (format stream " /* ~19@A = */ ~A,~%"
b426ab51
MW
612 (method-entry-slot-name entry)
613 (method-entry-function-name method chain-head role)))))))
a07d8d00
MW
614
615;;;--------------------------------------------------------------------------
3be8c2bf
MW
616;;; Filling in the class object.
617
7d8d3a16 618(defmethod hook-output ((ichain ichain) (reason (eql 'class)) sequencer)
4b8e5c03 619 (with-slots ((class %class) chain-head) ichain
3be8c2bf
MW
620 (sequence-output (stream sequencer)
621 :constraint ((*instance-class* :object :start)
622 (*instance-class* :object chain-head :ichain :start)
623 (*instance-class* :object chain-head :ichain :end)
624 (*instance-class* :object :end))
625 ((*instance-class* :object chain-head :ichain :start)
626 (format stream " { { /* ~A ichain */~%"
627 (sod-class-nickname chain-head)))
628 ((*instance-class* :object chain-head :ichain :end)
629 (format stream " } },~%")))))
630
7d8d3a16 631(defmethod hook-output ((islots islots) (reason (eql 'class)) sequencer)
4b8e5c03 632 (with-slots ((class %class)) islots
3be8c2bf
MW
633 (let ((chain-head (sod-class-chain-head class)))
634 (sequence-output (stream sequencer)
635 :constraint ((*instance-class* :object chain-head :ichain :start)
636 (*instance-class* :object class :slots :start)
637 (*instance-class* :object class :slots)
638 (*instance-class* :object class :slots :end)
639 (*instance-class* :object chain-head :ichain :end))
640 ((*instance-class* :object class :slots :start)
641 (format stream " { /* Class ~A */~%" class))
642 ((*instance-class* :object class :slots :end)
643 (format stream " },~%"))))))
644
7d8d3a16
MW
645(defmethod hook-output ((vtptr vtable-pointer)
646 (reason (eql 'class)) sequencer)
4b8e5c03 647 (with-slots ((class %class) chain-head chain-tail) vtptr
3be8c2bf
MW
648 (sequence-output (stream sequencer)
649 :constraint ((*instance-class* :object chain-head :ichain :start)
650 (*instance-class* :object chain-head :vtable)
651 (*instance-class* :object chain-head :ichain :end))
652 ((*instance-class* :object chain-head :vtable)
c2438e62
MW
653 (format stream " /* ~17@A = */ &~A.~A,~%"
654 "_vt"
655 (vtable-name class chain-head)
656 (sod-class-nickname chain-tail))))))
3be8c2bf 657
3be8c2bf
MW
658(defgeneric output-class-initializer (slot instance stream)
659 (:method ((slot sod-class-effective-slot) (instance sod-class) stream)
9ec578d9
MW
660 (let ((func (effective-slot-initializer-function slot))
661 (direct-slot (effective-slot-direct-slot slot)))
3be8c2bf 662 (if func
9ec578d9
MW
663 (format stream " /* ~15@A = */ ~A,~%"
664 (sod-slot-name direct-slot)
665 (funcall func instance))
3be8c2bf
MW
666 (call-next-method))))
667 (:method ((slot effective-slot) (instance sod-class) stream)
9ec578d9
MW
668 (let ((init (find-class-initializer slot instance))
669 (direct-slot (effective-slot-direct-slot slot)))
a888e3ac
MW
670 (format stream " /* ~15@A = */ ~A,~%"
671 (sod-slot-name direct-slot)
672 (sod-initializer-value init)))))
3be8c2bf 673
7d8d3a16
MW
674(defmethod hook-output ((slot sod-class-effective-slot)
675 (reason (eql 'class)) sequencer)
3be8c2bf
MW
676 (let ((instance *instance-class*)
677 (func (effective-slot-prepare-function slot)))
678 (when func
679 (sequence-output (stream sequencer)
680 ((instance :object :prepare)
7d8d3a16
MW
681 (funcall func instance stream)))))
682 (call-next-method))
3be8c2bf 683
7d8d3a16
MW
684(defmethod hook-output ((slot effective-slot)
685 (reason (eql 'class)) sequencer)
4b8e5c03 686 (with-slots ((class %class) (dslot slot)) slot
3be8c2bf
MW
687 (let ((instance *instance-class*)
688 (super (sod-slot-class dslot)))
689 (sequence-output (stream sequencer)
690 ((instance :object super :slots)
691 (output-class-initializer slot instance stream))))))
692
1f1d88f5 693;;;----- That's all, folks --------------------------------------------------