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