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