src/output-proto.lisp, etc. (hook-output): Use standard combination.
[sod] / src / class-output.lisp
1 ;;; -*-lisp-*-
2 ;;;
3 ;;; Output for classes
4 ;;;
5 ;;; (c) 2009 Straylight/Edgeware
6 ;;;
7
8 ;;;----- Licensing notice ---------------------------------------------------
9 ;;;
10 ;;; This file is part of the Sensible Object Design, an object system for C.
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 ;;; Walking the layout tree.
30
31 (defmethod hook-output :after ((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 :after ((ilayout ilayout) reason sequencer)
39 (with-slots (ichains) ilayout
40 (dolist (ichain ichains) (hook-output ichain reason sequencer))))
41
42 (defmethod hook-output :after ((ichain ichain) reason sequencer)
43 (dolist (item (ichain-body ichain)) (hook-output item reason sequencer)))
44
45 (defmethod hook-output :after ((islots islots) reason sequencer)
46 (dolist (slot (islots-slots islots)) (hook-output slot reason sequencer)))
47
48 (defmethod hook-output :after ((vtable vtable) reason sequencer)
49 (with-slots (body) vtable
50 (dolist (item body) (hook-output item reason sequencer))))
51
52 (defmethod hook-output :after ((vtmsgs vtmsgs) reason sequencer)
53 (with-slots (entries) vtmsgs
54 (dolist (entry entries) (hook-output entry reason sequencer))))
55
56 ;;;--------------------------------------------------------------------------
57 ;;; Classes.
58
59 (defmethod hook-output ((class sod-class) (reason (eql :h)) sequencer)
60
61 ;; Main output sequencing.
62 (sequence-output (stream sequencer)
63
64 :constraint
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)
71 (class :methods :start) (class :methods :defs)
72 (class :methods) (class :methods :end)
73 (class :ichains :start) (class :ichains :end)
74 (class :ilayout :start) (class :ilayout :slots) (class :ilayout :end)
75 (class :conversions)
76 (class :message-macros)
77 (class :object)
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)
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)))
95 (format stream "/* The class object. */~@
96 extern const struct ~A ~A__classobj;~@
97 #define ~:*~A__class (&~:*~A__classobj.~A.~A)~%"
98 (ilayout-struct-tag metaclass) class
99 (sod-class-nickname (sod-class-chain-head metaroot))
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))))
108
109 ;; Maybe generate an islots structure.
110 (when (sod-class-slots class)
111 (sequence-output (stream sequencer)
112 ((class :islots :start)
113 (format stream "/* Instance slots. */~@
114 struct ~A {~%"
115 (islots-struct-tag class)))
116 ((class :islots :end)
117 (format stream "};~2%"))))
118
119 ;; Declare the direct methods.
120 (when (sod-class-methods class)
121 (sequence-output (stream sequencer)
122 ((class :methods :start)
123 (format stream "/* Direct methods. */~%"))
124 ((class :methods :end)
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)))
132 (format stream "/* Conversion macros. */~%")
133 (dolist (super (cdr (sod-class-precedence-list class)))
134 (let ((super-head (sod-class-chain-head super)))
135 (format stream "#define ~:@(~A__CONV_~A~)(_obj) ((~A *)~
136 ~:[SOD_XCHAIN(~A, (_obj))~;(_obj)~])~%"
137 class (sod-class-nickname super) super
138 (eq chain-head super-head)
139 (sod-class-nickname super-head))))
140 (terpri stream)))))
141
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.
148 (when (some (lambda (message)
149 (or (keyword-message-p message)
150 (varargs-message-p message)))
151 (sod-class-messages class))
152 (one-off-output 'varargs-macros sequencer :early-decls
153 (lambda (stream)
154 (format stream
155 "~%SOD__VARARGS_MACROS_PREAMBLE~%"))))
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. */~%")
167 (dolist (entry (vtmsgs-entries vtmsgs))
168 (let* ((type (method-entry-function-type entry))
169 (args (c-function-arguments type))
170 (in-names nil) (out-names nil) (varargsp nil) (me "me"))
171 (do ((args args (cdr args)))
172 ((endp args))
173 (let* ((raw-name (princ-to-string (argument-name (car args))))
174 (name (if (find raw-name
175 (list "_vt"
176 (sod-class-nickname class)
177 (method-entry-slot-name entry))
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)
183 (unless in-names (setf me "SOD__CAR(__VA_ARGS__)"))
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
191 (format stream "#ifdef SOD__HAVE_VARARGS_MACROS~%"))
192 (format stream "#define ~A(~{~A~^, ~}) ~
193 (~A)->_vt->~A.~A(~{~A~^, ~})~%"
194 (message-macro-name class entry)
195 (nreverse in-names)
196 me
197 (sod-class-nickname class)
198 (method-entry-slot-name entry)
199 (nreverse out-names))
200 (when varargsp
201 (format stream "#endif~%"))))
202 (terpri stream))))))
203
204 (defmethod hook-output :after ((class sod-class) (reason (eql :h)) sequencer)
205
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.
211 (hook-output (car (sod-class-vtables class)) 'vtmsgs sequencer))
212
213 ;;;--------------------------------------------------------------------------
214 ;;; Instance structure.
215
216 (defmethod hook-output ((slot sod-slot) (reason (eql 'islots)) sequencer)
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
223 (defmethod hook-output ((ilayout ilayout) (reason (eql :h)) sequencer)
224 (with-slots ((class %class)) ilayout
225 (sequence-output (stream sequencer)
226 ((class :ilayout :start)
227 (format stream "/* Instance layout. */~@
228 struct ~A {~%"
229 (ilayout-struct-tag class)))
230 ((class :ilayout :end)
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)))
236
237 (defmethod hook-output ((ichain ichain) (reason (eql :h)) sequencer)
238 (with-slots ((class %class) chain-head chain-tail) ichain
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)
247 (format stream "/* Instance chain structure. */~@
248 struct ~A {~%"
249 (ichain-struct-tag chain-tail chain-head)))
250 ((class :ichain chain-head :end)
251 (format stream "};~2%")
252 (format stream "/* Union of equivalent superclass chains. */~@
253 union ~A {~@
254 ~:{ struct ~A ~A;~%~}~
255 };~2%"
256 (ichain-union-tag chain-tail chain-head)
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.
261 (mapcar (lambda (super)
262 (list (ichain-struct-tag super chain-head)
263 (sod-class-nickname super)))
264 (sod-class-chain chain-tail))))))))
265
266 (defmethod hook-output ((ichain ichain) (reason (eql 'ilayout)) sequencer)
267 (with-slots ((class %class) chain-head chain-tail) ichain
268 (sequence-output (stream sequencer)
269 ((class :ilayout :slots)
270 (format stream " union ~A ~A;~%"
271 (ichain-union-tag chain-tail chain-head)
272 (sod-class-nickname chain-head))))))
273
274 (defmethod hook-output ((vtptr vtable-pointer) (reason (eql :h)) sequencer)
275 (with-slots ((class %class) chain-head chain-tail) vtptr
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)))))))
281
282 (defmethod hook-output ((islots islots) (reason (eql :h)) sequencer)
283 (with-slots ((class %class) subclass slots) islots
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))))))))
291
292 ;;;--------------------------------------------------------------------------
293 ;;; Vtable structure.
294
295 (defmethod hook-output ((method sod-method) (reason (eql :h)) sequencer)
296 (with-slots ((class %class)) method
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))
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 {~%~
310 ~{ unsigned ~A: 1;~%~}~
311 };~2%"
312 (direct-method-suppliedp-struct-tag method)
313 (mapcar #'argument-name keys))))))))
314
315 (defmethod hook-output ((vtable vtable) (reason (eql :h)) sequencer)
316 (with-slots ((class %class) chain-head chain-tail) vtable
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)
325 (format stream "/* Vtable structure. */~@
326 struct ~A {~%"
327 (vtable-struct-tag chain-tail chain-head)))
328 ((class :vtable chain-head :end)
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))))))
342 (sequence-output (stream sequencer)
343 ((class :vtable-externs)
344 (format stream "~@<extern const union ~A ~2I~_~A;~:>~%"
345 (vtable-union-tag chain-tail chain-head)
346 (vtable-name class chain-head))))))
347
348 (defmethod hook-output ((vtmsgs vtmsgs) (reason (eql :h)) sequencer)
349 (with-slots ((class %class) subclass chain-head chain-tail) vtmsgs
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)))))))
356
357 (defmethod hook-output ((vtmsgs vtmsgs) (reason (eql 'vtmsgs)) sequencer)
358 (when (vtmsgs-entries vtmsgs)
359 (with-slots ((class %class) subclass) vtmsgs
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)
367 (format stream "/* Messages protocol from class ~A */~@
368 struct ~A {~%"
369 class
370 (vtmsgs-struct-tag subclass class)))
371 ((subclass :vtmsgs class :end)
372 (format stream "};~2%"))))))
373
374 (defmethod hook-output ((entry method-entry)
375 (reason (eql 'vtmsgs)) sequencer)
376 (let* ((method (method-entry-effective-method entry))
377 (message (effective-method-message method))
378 (class (effective-method-class method))
379 (function-type (method-entry-function-type entry))
380 (commented-type (commentify-function-type function-type))
381 (pointer-type (make-pointer-type commented-type)))
382 (sequence-output (stream sequencer)
383 ((class :vtmsgs (sod-message-class message) :slots)
384 (pprint-logical-block (stream nil :prefix " " :suffix ";")
385 (pprint-c-type pointer-type stream (method-entry-slot-name entry)))
386 (terpri stream)))))
387
388 (defmethod hook-output ((cptr class-pointer) (reason (eql :h)) sequencer)
389 (with-slots ((class %class) chain-head metaclass meta-chain-head) cptr
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))))))))
397
398 (defmethod hook-output ((boff base-offset) (reason (eql :h)) sequencer)
399 (with-slots ((class %class) chain-head) boff
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))))))
404
405 (defmethod hook-output ((choff chain-offset) (reason (eql :h)) sequencer)
406 (with-slots ((class %class) chain-head target-head) choff
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)))))))
412
413 ;;;--------------------------------------------------------------------------
414 ;;; Implementation output.
415
416 (export '*instance-class*)
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.")
426
427 (defmethod hook-output ((class sod-class) (reason (eql :c)) sequencer)
428 (sequence-output (stream sequencer)
429
430 :constraint
431 ((:classes :start)
432 (class :banner)
433 (class :direct-methods :start) (class :direct-methods :end)
434 (class :effective-methods)
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. */
445 const struct ~A ~A__classobj = {~%"
446 (ilayout-struct-tag (sod-class-metaclass class))
447 class))
448 ((class :object :end)
449 (format stream "};~2%"))))
450
451 (defmethod hook-output :after ((class sod-class) (reason (eql :c)) sequencer)
452 (let ((*instance-class* class))
453 (hook-output (sod-class-ilayout (sod-class-metaclass class))
454 'class sequencer)))
455
456 ;;;--------------------------------------------------------------------------
457 ;;; Direct and effective methods.
458
459 (defmethod hook-output ((method delegating-direct-method)
460 (reason (eql :c)) sequencer)
461 (with-slots ((class %class) body) method
462 (unless body
463 (return-from hook-output))
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)
471 (format stream "#undef CALL_NEXT_METHOD~%"))))
472 (call-next-method))
473
474 (defmethod hook-output ((method sod-method) (reason (eql :c)) sequencer)
475 (with-slots ((class %class) role body message) method
476 (unless body
477 (return-from hook-output))
478 (sequence-output (stream sequencer)
479 :constraint ((class :direct-methods :start)
480 (class :direct-method method :banner)
481 (class :direct-method method :start)
482 (class :direct-method method :body)
483 (class :direct-method method :end)
484 (class :direct-methods :end))
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))
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
504 (defmethod hook-output ((method basic-effective-method)
505 (reason (eql :c)) sequencer)
506 (with-slots ((class %class) functions) method
507 (sequence-output (stream sequencer)
508 ((class :effective-methods)
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))
520 (format stream "~{ unsigned ~A__suppliedp: 1;~%~}"
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%")))
527 (dolist (func functions)
528 (write func :stream stream :escape nil :circle nil))))))
529
530 ;;;--------------------------------------------------------------------------
531 ;;; Vtables.
532
533 (defmethod hook-output ((vtable vtable) (reason (eql :c)) sequencer)
534 (with-slots ((class %class) chain-head chain-tail) vtable
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. */~@
542 const union ~A ~A = { {~%"
543 chain-head
544 (vtable-union-tag chain-tail chain-head)
545 (vtable-name class chain-head)))
546 ((class :vtable chain-head :end)
547 (format stream "} };~2%")))))
548
549 (defmethod hook-output ((cptr class-pointer) (reason (eql :c)) sequencer)
550 (with-slots ((class %class) chain-head metaclass meta-chain-head) cptr
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)
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")
561 class
562 (sod-class-nickname meta-chain-head)
563 (sod-class-nickname metaclass))))))
564
565 (defmethod hook-output ((boff base-offset) (reason (eql :c)) sequencer)
566 (with-slots ((class %class) chain-head) boff
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)
572 (format stream " /* ~21@A = */ offsetof(struct ~A, ~A),~%"
573 "_base"
574 (ilayout-struct-tag class)
575 (sod-class-nickname chain-head))))))
576
577 (defmethod hook-output ((choff chain-offset) (reason (eql :c)) sequencer)
578 (with-slots ((class %class) chain-head target-head) choff
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)
584 (format stream " /* ~21@A = */ SOD_OFFSETDIFF(struct ~A, ~A, ~A),~%"
585 (format nil "_off_~A" (sod-class-nickname target-head))
586 (ilayout-struct-tag class)
587 (sod-class-nickname chain-head)
588 (sod-class-nickname target-head))))))
589
590 (defmethod hook-output ((vtmsgs vtmsgs) (reason (eql :c)) sequencer)
591 (with-slots ((class %class) subclass chain-head) vtmsgs
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
604 (defmethod hook-output ((entry method-entry) (reason (eql :c)) sequencer)
605 (with-slots ((method %method) chain-head chain-tail role) entry
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)
611 (format stream " /* ~19@A = */ ~A,~%"
612 (method-entry-slot-name entry)
613 (method-entry-function-name method chain-head role)))))))
614
615 ;;;--------------------------------------------------------------------------
616 ;;; Filling in the class object.
617
618 (defmethod hook-output ((ichain ichain) (reason (eql 'class)) sequencer)
619 (with-slots ((class %class) chain-head) ichain
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
631 (defmethod hook-output ((islots islots) (reason (eql 'class)) sequencer)
632 (with-slots ((class %class)) islots
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
645 (defmethod hook-output ((vtptr vtable-pointer)
646 (reason (eql 'class)) sequencer)
647 (with-slots ((class %class) chain-head chain-tail) vtptr
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)
653 (format stream " /* ~17@A = */ &~A.~A,~%"
654 "_vt"
655 (vtable-name class chain-head)
656 (sod-class-nickname chain-tail))))))
657
658 (defgeneric output-class-initializer (slot instance stream)
659 (:method ((slot sod-class-effective-slot) (instance sod-class) stream)
660 (let ((func (effective-slot-initializer-function slot))
661 (direct-slot (effective-slot-direct-slot slot)))
662 (if func
663 (format stream " /* ~15@A = */ ~A,~%"
664 (sod-slot-name direct-slot)
665 (funcall func instance))
666 (call-next-method))))
667 (:method ((slot effective-slot) (instance sod-class) stream)
668 (let ((init (find-class-initializer slot instance))
669 (direct-slot (effective-slot-direct-slot slot)))
670 (format stream " /* ~15@A = */ ~A,~%"
671 (sod-slot-name direct-slot)
672 (sod-initializer-value init)))))
673
674 (defmethod hook-output ((slot sod-class-effective-slot)
675 (reason (eql 'class)) sequencer)
676 (let ((instance *instance-class*)
677 (func (effective-slot-prepare-function slot)))
678 (when func
679 (sequence-output (stream sequencer)
680 ((instance :object :prepare)
681 (funcall func instance stream)))))
682 (call-next-method))
683
684 (defmethod hook-output ((slot effective-slot)
685 (reason (eql 'class)) sequencer)
686 (with-slots ((class %class) (dslot slot)) slot
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
693 ;;;----- That's all, folks --------------------------------------------------