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