src/utilities.lisp (dosequence): Capture SEQ as a variable explicitly.
[sod] / src / class-output.lisp
CommitLineData
1f1d88f5
MW
1;;; -*-lisp-*-
2;;;
dea4d055 3;;; Output for classes
1f1d88f5
MW
4;;;
5;;; (c) 2009 Straylight/Edgeware
6;;;
7
8;;;----- Licensing notice ---------------------------------------------------
9;;;
e0808c47 10;;; This file is part of the Sensible Object Design, an object system for C.
1f1d88f5
MW
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;;;--------------------------------------------------------------------------
6e2d4b52
MW
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)
1224dfb0 43 (dolist (item (ichain-body ichain)) (hook-output item reason sequencer)))
6e2d4b52
MW
44
45(defmethod hook-output progn ((islots islots) reason sequencer)
1224dfb0 46 (dolist (slot (islots-slots islots)) (hook-output slot reason sequencer)))
6e2d4b52
MW
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;;;--------------------------------------------------------------------------
1f1d88f5
MW
57;;; Classes.
58
5b0a2bdb 59(defmethod hook-output progn ((class sod-class) (reason (eql :h)) sequencer)
1f1d88f5
MW
60
61 ;; Main output sequencing.
62 (sequence-output (stream sequencer)
63
64 :constraint
1f1d88f5
MW
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)
43073476
MW
71 (class :methods :start) (class :methods :defs)
72 (class :methods) (class :methods :end)
1f1d88f5
MW
73 (class :ichains :start) (class :ichains :end)
74 (class :ilayout :start) (class :ilayout :slots) (class :ilayout :end)
75 (class :conversions)
6bc944c3 76 (class :message-macros)
ddee4bb1 77 (class :object)
1f1d88f5
MW
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)
ddee4bb1
MW
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)))
a07d8d00
MW
95 (format stream "/* The class object. */~@
96 extern const struct ~A ~A__classobj;~@
489173a5 97 #define ~:*~A__class (&~:*~A__classobj.~A.~A)~%"
ddee4bb1
MW
98 (ilayout-struct-tag metaclass) class
99 (sod-class-nickname (sod-class-chain-head metaroot))
489173a5
MW
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))))
1f1d88f5
MW
108
109 ;; Maybe generate an islots structure.
110 (when (sod-class-slots class)
111 (dolist (slot (sod-class-slots class))
dea4d055 112 (hook-output slot 'islots sequencer))
1f1d88f5
MW
113 (sequence-output (stream sequencer)
114 ((class :islots :start)
a07d8d00 115 (format stream "/* Instance slots. */~@
ddee4bb1
MW
116 struct ~A {~%"
117 (islots-struct-tag class)))
1f1d88f5
MW
118 ((class :islots :end)
119 (format stream "};~2%"))))
120
121 ;; Declare the direct methods.
122 (when (sod-class-methods class)
1f1d88f5 123 (sequence-output (stream sequencer)
ddee4bb1
MW
124 ((class :methods :start)
125 (format stream "/* Direct methods. */~%"))
126 ((class :methods :end)
1f1d88f5
MW
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)))
ddee4bb1 134 (format stream "/* Conversion macros. */~%")
1f1d88f5
MW
135 (dolist (super (cdr (sod-class-precedence-list class)))
136 (let ((super-head (sod-class-chain-head super)))
bb172d53
MW
137 (format stream "#define ~:@(~A__CONV_~A~)(_obj) ((~A *)~
138 ~:[SOD_XCHAIN(~A, (_obj))~;(_obj)~])~%"
1f1d88f5
MW
139 class (sod-class-nickname super) super
140 (eq chain-head super-head)
ddee4bb1
MW
141 (sod-class-nickname super-head))))
142 (terpri stream)))))
1f1d88f5 143
6bc944c3
MW
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.
43073476
MW
150 (when (some (lambda (message)
151 (or (keyword-message-p message)
152 (varargs-message-p message)))
153 (sod-class-messages class))
e674612e
MW
154 (one-off-output 'varargs-macros sequencer :early-decls
155 (lambda (stream)
156 (format stream
157 "~%SOD__VARARGS_MACROS_PREAMBLE~%"))))
6bc944c3
MW
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. */~%")
6bc944c3
MW
169 (dolist (entry (vtmsgs-entries vtmsgs))
170 (let* ((type (method-entry-function-type entry))
171 (args (c-function-arguments type))
6bc944c3
MW
172 (in-names nil) (out-names nil) (varargsp nil) (me "me"))
173 (do ((args args (cdr args)))
174 ((endp args))
b426ab51 175 (let* ((raw-name (princ-to-string (argument-name (car args))))
6bc944c3
MW
176 (name (if (find raw-name
177 (list "_vt"
178 (sod-class-nickname class)
b426ab51 179 (method-entry-slot-name entry))
6bc944c3
MW
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)
68a4f8c9 185 (unless in-names (setf me "SOD__CAR(__VA_ARGS__)"))
6bc944c3
MW
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
e674612e 193 (format stream "#ifdef SOD__HAVE_VARARGS_MACROS~%"))
6bc944c3 194 (format stream "#define ~A(~{~A~^, ~}) ~
d908a89e 195 (~A)->_vt->~A.~A(~{~A~^, ~})~%"
b426ab51 196 (message-macro-name class entry)
6bc944c3
MW
197 (nreverse in-names)
198 me
199 (sod-class-nickname class)
b426ab51 200 (method-entry-slot-name entry)
6bc944c3
MW
201 (nreverse out-names))
202 (when varargsp
203 (format stream "#endif~%"))))
204 (terpri stream)))))
205
1f1d88f5 206 ;; Generate vtmsgs structure for all superclasses.
6e2d4b52 207 (hook-output (car (sod-class-vtables class)) 'vtmsgs sequencer))
1f1d88f5
MW
208
209;;;--------------------------------------------------------------------------
210;;; Instance structure.
211
1224dfb0
MW
212(defmethod hook-output progn
213 ((slot sod-slot) (reason (eql 'islots)) sequencer)
1f1d88f5
MW
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
5b0a2bdb 220(defmethod hook-output progn ((ilayout ilayout) (reason (eql :h)) sequencer)
4b8e5c03 221 (with-slots ((class %class) ichains) ilayout
1f1d88f5
MW
222 (sequence-output (stream sequencer)
223 ((class :ilayout :start)
a07d8d00 224 (format stream "/* Instance layout. */~@
ddee4bb1
MW
225 struct ~A {~%"
226 (ilayout-struct-tag class)))
1f1d88f5
MW
227 ((class :ilayout :end)
228 (format stream "};~2%")))
229 (dolist (ichain ichains)
dea4d055 230 (hook-output ichain 'ilayout sequencer))))
1f1d88f5 231
5b0a2bdb 232(defmethod hook-output progn ((ichain ichain) (reason (eql :h)) sequencer)
4b8e5c03 233 (with-slots ((class %class) chain-head chain-tail) ichain
ddee4bb1
MW
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)
a07d8d00 242 (format stream "/* Instance chain structure. */~@
ddee4bb1
MW
243 struct ~A {~%"
244 (ichain-struct-tag chain-tail chain-head)))
245 ((class :ichain chain-head :end)
246 (format stream "};~2%")
a07d8d00
MW
247 (format stream "/* Union of equivalent superclass chains. */~@
248 union ~A {~@
ddee4bb1
MW
249 ~:{ struct ~A ~A;~%~}~
250 };~2%"
251 (ichain-union-tag chain-tail chain-head)
dea4d055
MW
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.
ddee4bb1
MW
256 (mapcar (lambda (super)
257 (list (ichain-struct-tag super chain-head)
258 (sod-class-nickname super)))
259 (sod-class-chain chain-tail))))))))
1f1d88f5 260
1224dfb0
MW
261(defmethod hook-output progn
262 ((ichain ichain) (reason (eql 'ilayout)) sequencer)
4b8e5c03 263 (with-slots ((class %class) chain-head chain-tail) ichain
1f1d88f5
MW
264 (sequence-output (stream sequencer)
265 ((class :ilayout :slots)
ddee4bb1
MW
266 (format stream " union ~A ~A;~%"
267 (ichain-union-tag chain-tail chain-head)
1f1d88f5
MW
268 (sod-class-nickname chain-head))))))
269
5b0a2bdb
MW
270(defmethod hook-output progn ((vtptr vtable-pointer)
271 (reason (eql :h))
272 sequencer)
4b8e5c03 273 (with-slots ((class %class) chain-head chain-tail) vtptr
64fd357d
MW
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)))))))
1f1d88f5 279
5b0a2bdb 280(defmethod hook-output progn ((islots islots) (reason (eql :h)) sequencer)
4b8e5c03 281 (with-slots ((class %class) subclass slots) islots
64fd357d
MW
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))))))))
1f1d88f5
MW
289
290;;;--------------------------------------------------------------------------
291;;; Vtable structure.
292
1224dfb0
MW
293(defmethod hook-output progn
294 ((method sod-method) (reason (eql :h)) sequencer)
4b8e5c03 295 (with-slots ((class %class)) method
ddee4bb1
MW
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))
43073476
MW
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 {~%~
fd040f06 309 ~{ unsigned ~A: 1;~%~}~
43073476
MW
310 };~2%"
311 (direct-method-suppliedp-struct-tag method)
312 (mapcar #'argument-name keys))))))))
ddee4bb1 313
5b0a2bdb 314(defmethod hook-output progn ((vtable vtable) (reason (eql :h)) sequencer)
4b8e5c03 315 (with-slots ((class %class) chain-head chain-tail) vtable
ddee4bb1
MW
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)
a07d8d00 324 (format stream "/* Vtable structure. */~@
ddee4bb1
MW
325 struct ~A {~%"
326 (vtable-struct-tag chain-tail chain-head)))
327 ((class :vtable chain-head :end)
c2438e62
MW
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))))))
1f1d88f5 341 (sequence-output (stream sequencer)
1f1d88f5 342 ((class :vtable-externs)
7c3bae74 343 (format stream "~@<extern const union ~A ~2I~_~A;~:>~%"
c2438e62 344 (vtable-union-tag chain-tail chain-head)
7c3bae74 345 (vtable-name class chain-head))))))
1f1d88f5 346
5b0a2bdb 347(defmethod hook-output progn ((vtmsgs vtmsgs) (reason (eql :h)) sequencer)
4b8e5c03 348 (with-slots ((class %class) subclass chain-head chain-tail) vtmsgs
64fd357d
MW
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)))))))
1f1d88f5 355
1224dfb0
MW
356(defmethod hook-output progn
357 ((vtmsgs vtmsgs) (reason (eql 'vtmsgs)) sequencer)
1f1d88f5 358 (when (vtmsgs-entries vtmsgs)
4b8e5c03 359 (with-slots ((class %class) subclass) vtmsgs
1f1d88f5
MW
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)
a07d8d00 367 (format stream "/* Messages protocol from class ~A */~@
ddee4bb1
MW
368 struct ~A {~%"
369 class
370 (vtmsgs-struct-tag subclass class)))
1f1d88f5
MW
371 ((subclass :vtmsgs class :end)
372 (format stream "};~2%"))))))
373
1224dfb0
MW
374(defmethod hook-output progn
375 ((entry method-entry) (reason (eql 'vtmsgs)) sequencer)
ddee4bb1
MW
376 (let* ((method (method-entry-effective-method entry))
377 (message (effective-method-message method))
1f1d88f5 378 (class (effective-method-class method))
9ec578d9
MW
379 (function-type (method-entry-function-type entry))
380 (commented-type (commentify-function-type function-type))
381 (pointer-type (make-pointer-type commented-type)))
1f1d88f5
MW
382 (sequence-output (stream sequencer)
383 ((class :vtmsgs (sod-message-class message) :slots)
384 (pprint-logical-block (stream nil :prefix " " :suffix ";")
b426ab51 385 (pprint-c-type pointer-type stream (method-entry-slot-name entry)))
1f1d88f5
MW
386 (terpri stream)))))
387
1224dfb0
MW
388(defmethod hook-output progn
389 ((cptr class-pointer) (reason (eql :h)) sequencer)
4b8e5c03 390 (with-slots ((class %class) chain-head metaclass meta-chain-head) cptr
64fd357d
MW
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))))))))
1f1d88f5 398
5b0a2bdb 399(defmethod hook-output progn ((boff base-offset) (reason (eql :h)) sequencer)
4b8e5c03 400 (with-slots ((class %class) chain-head) boff
64fd357d
MW
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))))))
1f1d88f5 405
1224dfb0
MW
406(defmethod hook-output progn
407 ((choff chain-offset) (reason (eql :h)) sequencer)
4b8e5c03 408 (with-slots ((class %class) chain-head target-head) choff
64fd357d
MW
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)))))))
1f1d88f5
MW
414
415;;;--------------------------------------------------------------------------
3be8c2bf
MW
416;;; Implementation output.
417
6e2d4b52 418(export '*instance-class*)
4b856491
MW
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.")
3be8c2bf 428
5b0a2bdb 429(defmethod hook-output progn ((class sod-class) (reason (eql :c)) sequencer)
3be8c2bf
MW
430 (sequence-output (stream sequencer)
431
432 :constraint
433 ((:classes :start)
434 (class :banner)
435 (class :direct-methods :start) (class :direct-methods :end)
a07d8d00 436 (class :effective-methods)
3be8c2bf
MW
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. */
447const 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))
dea4d055 454 (hook-output (sod-class-ilayout (sod-class-metaclass class))
6e2d4b52 455 'class sequencer)))
3be8c2bf
MW
456
457;;;--------------------------------------------------------------------------
9ec578d9 458;;; Direct and effective methods.
3be8c2bf 459
1224dfb0
MW
460(defmethod hook-output progn
461 ((method delegating-direct-method) (reason (eql :c)) sequencer)
4b8e5c03 462 (with-slots ((class %class) body) method
3be8c2bf 463 (unless body
dea4d055 464 (return-from hook-output))
3be8c2bf
MW
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
1224dfb0
MW
474(defmethod hook-output progn
475 ((method sod-method) (reason (eql :c)) sequencer)
7de8c666 476 (with-slots ((class %class) role body message) method
3be8c2bf 477 (unless body
dea4d055 478 (return-from hook-output))
3be8c2bf
MW
479 (sequence-output (stream sequencer)
480 :constraint ((class :direct-methods :start)
7de8c666 481 (class :direct-method method :banner)
3be8c2bf
MW
482 (class :direct-method method :start)
483 (class :direct-method method :body)
484 (class :direct-method method :end)
485 (class :direct-methods :end))
7de8c666
MW
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))
3be8c2bf
MW
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
1224dfb0
MW
505(defmethod hook-output progn
506 ((method basic-effective-method) (reason (eql :c)) sequencer)
4b8e5c03 507 (with-slots ((class %class) functions) method
dea4d055
MW
508 (sequence-output (stream sequencer)
509 ((class :effective-methods)
43073476
MW
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))
fd040f06 521 (format stream "~{ unsigned ~A__suppliedp: 1;~%~}"
43073476
MW
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%")))
dea4d055
MW
528 (dolist (func functions)
529 (write func :stream stream :escape nil :circle nil))))))
530
3be8c2bf 531;;;--------------------------------------------------------------------------
a07d8d00
MW
532;;; Vtables.
533
5b0a2bdb 534(defmethod hook-output progn ((vtable vtable) (reason (eql :c)) sequencer)
4b8e5c03 535 (with-slots ((class %class) chain-head chain-tail) vtable
a07d8d00
MW
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. */~@
c2438e62 543 const union ~A ~A = { {~%"
a07d8d00 544 chain-head
c2438e62 545 (vtable-union-tag chain-tail chain-head)
9ec578d9 546 (vtable-name class chain-head)))
a07d8d00 547 ((class :vtable chain-head :end)
c2438e62 548 (format stream "} };~2%")))))
a07d8d00 549
1224dfb0
MW
550(defmethod hook-output progn
551 ((cptr class-pointer) (reason (eql :c)) sequencer)
4b8e5c03 552 (with-slots ((class %class) chain-head metaclass meta-chain-head) cptr
a07d8d00
MW
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)
9ec578d9
MW
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")
fc5d9486 563 class
a07d8d00
MW
564 (sod-class-nickname meta-chain-head)
565 (sod-class-nickname metaclass))))))
566
5b0a2bdb 567(defmethod hook-output progn ((boff base-offset) (reason (eql :c)) sequencer)
4b8e5c03 568 (with-slots ((class %class) chain-head) boff
a07d8d00
MW
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)
9ec578d9
MW
574 (format stream " /* ~21@A = */ offsetof(struct ~A, ~A),~%"
575 "_base"
a07d8d00
MW
576 (ilayout-struct-tag class)
577 (sod-class-nickname chain-head))))))
578
1224dfb0
MW
579(defmethod hook-output progn
580 ((choff chain-offset) (reason (eql :c)) sequencer)
4b8e5c03 581 (with-slots ((class %class) chain-head target-head) choff
a07d8d00
MW
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)
9ec578d9
MW
587 (format stream " /* ~21@A = */ SOD_OFFSETDIFF(struct ~A, ~A, ~A),~%"
588 (format nil "_off_~A" (sod-class-nickname target-head))
a07d8d00
MW
589 (ilayout-struct-tag class)
590 (sod-class-nickname chain-head)
591 (sod-class-nickname target-head))))))
592
5b0a2bdb 593(defmethod hook-output progn ((vtmsgs vtmsgs) (reason (eql :c)) sequencer)
4b8e5c03 594 (with-slots ((class %class) subclass chain-head) vtmsgs
a07d8d00
MW
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
1224dfb0
MW
607(defmethod hook-output progn
608 ((entry method-entry) (reason (eql :c)) sequencer)
4b8e5c03 609 (with-slots ((method %method) chain-head chain-tail role) entry
a07d8d00
MW
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)
9ec578d9 615 (format stream " /* ~19@A = */ ~A,~%"
b426ab51
MW
616 (method-entry-slot-name entry)
617 (method-entry-function-name method chain-head role)))))))
a07d8d00
MW
618
619;;;--------------------------------------------------------------------------
3be8c2bf
MW
620;;; Filling in the class object.
621
1224dfb0
MW
622(defmethod hook-output progn
623 ((ichain ichain) (reason (eql 'class)) sequencer)
4b8e5c03 624 (with-slots ((class %class) chain-head) ichain
3be8c2bf
MW
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
1224dfb0
MW
636(defmethod hook-output progn
637 ((islots islots) (reason (eql 'class)) sequencer)
4b8e5c03 638 (with-slots ((class %class)) islots
3be8c2bf
MW
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
1224dfb0
MW
651(defmethod hook-output progn
652 ((vtptr vtable-pointer) (reason (eql 'class)) sequencer)
4b8e5c03 653 (with-slots ((class %class) chain-head chain-tail) vtptr
3be8c2bf
MW
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)
c2438e62
MW
659 (format stream " /* ~17@A = */ &~A.~A,~%"
660 "_vt"
661 (vtable-name class chain-head)
662 (sod-class-nickname chain-tail))))))
3be8c2bf 663
3be8c2bf
MW
664(defgeneric output-class-initializer (slot instance stream)
665 (:method ((slot sod-class-effective-slot) (instance sod-class) stream)
9ec578d9
MW
666 (let ((func (effective-slot-initializer-function slot))
667 (direct-slot (effective-slot-direct-slot slot)))
3be8c2bf 668 (if func
9ec578d9
MW
669 (format stream " /* ~15@A = */ ~A,~%"
670 (sod-slot-name direct-slot)
671 (funcall func instance))
3be8c2bf
MW
672 (call-next-method))))
673 (:method ((slot effective-slot) (instance sod-class) stream)
9ec578d9
MW
674 (let ((init (find-class-initializer slot instance))
675 (direct-slot (effective-slot-direct-slot slot)))
a888e3ac
MW
676 (format stream " /* ~15@A = */ ~A,~%"
677 (sod-slot-name direct-slot)
678 (sod-initializer-value init)))))
3be8c2bf 679
1224dfb0
MW
680(defmethod hook-output progn
681 ((slot sod-class-effective-slot) (reason (eql 'class)) sequencer)
3be8c2bf
MW
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
1224dfb0
MW
689(defmethod hook-output progn
690 ((slot effective-slot) (reason (eql 'class)) sequencer)
4b8e5c03 691 (with-slots ((class %class) (dslot slot)) slot
3be8c2bf
MW
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
1f1d88f5 698;;;----- That's all, folks --------------------------------------------------