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