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