debian/*.install: Distribute manpages with appropriate packages.
[sod] / src / builtin.lisp
CommitLineData
dea4d055
MW
1;;; -*-lisp-*-
2;;;
3;;; Builtin module provides the root of the class graph
4;;;
5;;; (c) 2009 Straylight/Edgeware
6;;;
7
8;;;----- Licensing notice ---------------------------------------------------
9;;;
10;;; This file is part of the Sensble 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;;; Infrastructure.
30
31(defvar *class-slot-alist* nil)
32
33(defun add-class-slot-function (name function)
ea578bb4 34 "Attach a slot function to the `*class-slot-alist*'.
dea4d055
MW
35
36 The FUNCTION is invoked with one argument, which is a `sod-class' object
37 to which it should add a slot. If a function with the same NAME is
38 already defined then that function is replaced; otherwise a new name/
39 function pair is defined.
40
41 Functions are are invoked in the order in which their names were first
42 added."
43
44 (aif (assoc name *class-slot-alist* :test #'string=)
45 (setf (cdr it) function)
46 (asetf *class-slot-alist* (append it (list (cons name function))))))
47
48(defmacro define-class-slot
49 (name (class &optional stream) type init &body prepare)
50 "Define a new class slot.
51
ea578bb4
MW
52 The slot will be called NAME (a string) and will be of TYPE (which should
53 be a type S-expression). The slot's (static) initializer will be
54 constructed by printing the value of INIT, which is evaluated with CLASS
55 bound to the class object being constructed. If any PREPARE forms are
56 provided, then they are evaluated as a progn, with CLASS bound to the
dea4d055
MW
57 class object, and STREAM bound to the output stream it should write on."
58
59 (with-gensyms (classvar)
60 `(add-class-slot-function
61 ',name
62 (lambda (,classvar)
63 (make-sod-slot ,classvar ,name (c-type ,type)
52a79ab8 64 (make-property-set :slot-class 'sod-class-slot
dea4d055
MW
65 :initializer-function
66 (lambda (,class)
67 ,init)
68 ,@(and prepare
69 `(:prepare-function
70 (lambda (,class ,stream)
71 ,@prepare)))))))))
72
73;;;--------------------------------------------------------------------------
74;;; Basic information.
75
76(define-class-slot "name" (class) const-string
77 (prin1-to-string (sod-class-name class)))
78
79(define-class-slot "nick" (class) const-string
80 (prin1-to-string (sod-class-nickname class)))
81
82;;;--------------------------------------------------------------------------
83;;; Instance allocation and initialization.
84
85(define-class-slot "initsz" (class) size-t
86 (format nil "sizeof(struct ~A)" (ilayout-struct-tag class)))
87
88(define-class-slot "imprint" (class stream)
89 (* (fun (* void) ("/*p*/" (* void))))
90 (format nil "~A__imprint" class)
91 (let ((ilayout (sod-class-ilayout class)))
92 (format stream "~&~:
93/* Imprint raw memory with instance structure. */
94static void *~A__imprint(void *p)
95{
96 struct ~A *sod__obj = p;
97
c2438e62 98 ~:{sod__obj->~A.~A._vt = &~A.~A;~:^~% ~}
dea4d055
MW
99 return (p);
100}~2%"
101 class
102 (ilayout-struct-tag class)
103 (mapcar (lambda (ichain)
104 (let* ((head (ichain-head ichain))
105 (tail (ichain-tail ichain)))
106 (list (sod-class-nickname head)
107 (sod-class-nickname tail)
c2438e62
MW
108 (vtable-name class head)
109 (sod-class-nickname tail))))
dea4d055
MW
110 (ilayout-ichains ilayout)))))
111
112(define-class-slot "init" (class stream)
113 (* (fun (* void) ("/*p*/" (* void))))
114 (format nil "~A__init" class)
115
116 ;; FIXME this needs a metaobject protocol
ea578bb4
MW
117 (let ((ilayout (sod-class-ilayout class))
118 (used nil))
dea4d055 119 (format stream "~&~:
ea578bb4
MW
120/* Provide initial values for an instance's slots. */
121static void *~A__init(void *p)~%{~%" class)
dea4d055 122 (dolist (ichain (ilayout-ichains ilayout))
ea578bb4 123 (let ((ich (format nil "sod__obj->~A.~A"
dea4d055
MW
124 (sod-class-nickname (ichain-head ichain))
125 (sod-class-nickname (ichain-tail ichain)))))
126 (dolist (item (ichain-body ichain))
127 (etypecase item
128 (vtable-pointer
129 nil)
130 (islots
131 (let ((isl (format nil "~A.~A"
132 ich
133 (sod-class-nickname (islots-class item)))))
134 (dolist (slot (islots-slots item))
135 (let ((dslot (effective-slot-direct-slot slot))
136 (init (effective-slot-initializer slot)))
137 (when init
ea578bb4
MW
138 (unless used
139 (format stream
9ec578d9
MW
140 " struct ~A *sod__obj = ~A__imprint(p);~2%"
141 (ilayout-struct-tag class) class)
ea578bb4 142 (setf used t))
1d8206e9
MW
143 (format stream " {~% ~A ~A ="
144 (sod-slot-type dslot)
145 *sod-tmp-val*)
dea4d055
MW
146 (ecase (sod-initializer-value-kind init)
147 (:simple (write (sod-initializer-value-form init)
148 :stream stream
149 :pretty nil :escape nil)
150 (format stream ";~%"))
1d8206e9 151 (:compound (format stream " {")
dea4d055
MW
152 (write (sod-initializer-value-form init)
153 :stream stream
154 :pretty nil :escape nil)
1d8206e9
MW
155 (format stream " };~%")))
156 (format stream " ~A.~A = ~A;~% }~%"
157 isl (sod-slot-name dslot)
158 *sod-tmp-val*))))))))))
ea578bb4
MW
159 (unless used
160 (format stream " ~A__imprint(p);~%" class))
dea4d055
MW
161 (format stream "~&~:
162 return (p);
163}~2%")))
164
165;;;--------------------------------------------------------------------------
166;;; Superclass structure.
167
168(define-class-slot "n_supers" (class) size-t
169 (length (sod-class-direct-superclasses class)))
170
171(define-class-slot "supers" (class stream)
172 (* (* (class "SodClass" :const) :const))
173 (if (null (sod-class-direct-superclasses class)) 0
174 (format nil "~A__supers" class))
175 (let ((supers (sod-class-direct-superclasses class)))
176 (when supers
177 (format stream "~&~:
178/* Direct superclasses. */
179static const SodClass *const ~A__supers[] = {
180 ~{~A__class~^,~% ~}
181};~2%"
182 class supers))))
183
184(define-class-slot "n_cpl" (class) size-t
185 (length (sod-class-precedence-list class)))
186
187(define-class-slot "cpl" (class stream)
188 (* (* (class "SodClass" :const) :const))
189 (format nil "~A__cpl" class)
190 (format stream "~&~:
191/* Class precedence list. */
192static const SodClass *const ~A__cpl[] = {
193 ~{~A__class~^,~% ~}
194};~2%"
195 class (sod-class-precedence-list class)))
196
197;;;--------------------------------------------------------------------------
198;;; Chain structure.
199
200(define-class-slot "link" (class) (* (class "SodClass" :const))
201 (aif (sod-class-chain-link class)
202 (format nil "~A__class" it)
203 0))
204
205(define-class-slot "head" (class) (* (class "SodClass" :const))
206 (format nil "~A__class" (sod-class-chain-head class)))
207
208(define-class-slot "level" (class) size-t
209 (position class (reverse (sod-class-chain class))))
210
211(define-class-slot "n_chains" (class) size-t
212 (length (sod-class-chains class)))
213
214(define-class-slot "chains" (class stream) (* (struct "sod_chain" :const))
215 (format nil "~A__chains" class)
216 (let ((chains (sod-class-chains class)))
217 (format stream "~&~:
218/* Chain structure. */
219~1@*~:{static const SodClass *const ~A__chain_~A[] = {
220 ~{~A__class~^,~% ~}
221};~:^~2%~}
222
223~0@*static const struct sod_chain ~A__chains[] = {
9ec578d9
MW
224~:{ { ~
225 /* n_classes = */ ~3@*~A,
226 /* classes = */ ~0@*~A__chain_~A,
227 /* off_ichain = */ ~4@*offsetof(struct ~A, ~A),
228 /* vt = */ (const struct sod_vtable *)&~A,
229 /* ichainsz = */ sizeof(struct ~A) }~:^,~%~}
dea4d055
MW
230};~2%"
231 class ;0
232 (mapcar (lambda (chain) ;1
233 (let* ((head (sod-class-chain-head (car chain)))
234 (chain-nick (sod-class-nickname head)))
9ec578d9
MW
235 (list class chain-nick ;0 1
236 (reverse chain) ;2
237 (length chain) ;3
238 (ilayout-struct-tag class) chain-nick ;4 5
239 (vtable-name class head) ;6
240 (ichain-struct-tag (car chain) head)))) ;7
dea4d055
MW
241 chains))))
242
243;;;--------------------------------------------------------------------------
244;;; Class-specific layout.
245
246(define-class-slot "off_islots" (class) size-t
9ec578d9
MW
247 (if (sod-class-slots class)
248 (format nil "offsetof(struct ~A, ~A)"
249 (ichain-struct-tag class (sod-class-chain-head class))
250 (sod-class-nickname class))
251 "0"))
dea4d055
MW
252
253(define-class-slot "islotsz" (class) size-t
9ec578d9
MW
254 (if (sod-class-slots class)
255 (format nil "sizeof(struct ~A)"
256 (islots-struct-tag class))
257 "0"))
dea4d055
MW
258
259;;;--------------------------------------------------------------------------
260;;; Bootstrapping the class graph.
261
262(defun bootstrap-classes (module)
ea578bb4
MW
263 "Bootstrap the braid in MODULE.
264
265 This builds the fundamental recursive braid, where `SodObject' is an
266 instance of `SodClass', and `SodClass' is a subclass of `SodObject' (and
267 an instance of itself)."
dea4d055
MW
268 (let* ((sod-object (make-sod-class "SodObject" nil
269 (make-property-set :nick 'obj)))
270 (sod-class (make-sod-class "SodClass" (list sod-object)
271 (make-property-set :nick 'cls)))
272 (classes (list sod-object sod-class)))
273
274 ;; Sort out the recursion.
275 (setf (slot-value sod-class 'chain-link) sod-object)
276 (dolist (class classes)
277 (setf (slot-value class 'metaclass) sod-class))
278
279 ;; Predeclare the class types.
280 (dolist (class classes)
281 (make-class-type (sod-class-name class)))
282
283 ;; Attach the class slots.
284 (dolist (slot *class-slot-alist*)
285 (funcall (cdr slot) sod-class))
286
287 ;; These classes are too closely intertwined. We must partially finalize
288 ;; them together by hand. This is cloned from `finalize-sod-class'.
289 (dolist (class classes)
290 (with-slots (class-precedence-list chain-head chain chains) class
291 (setf class-precedence-list (compute-cpl class))
292 (setf (values chain-head chain chains) (compute-chains class))))
293
294 ;; Done.
295 (dolist (class classes)
296 (finalize-sod-class class)
297 (add-to-module module class))))
298
73c17a81 299(export '*builtin-module*)
ea578bb4
MW
300(defvar *builtin-module* nil
301 "The builtin module.")
302
73c17a81 303(export 'make-builtin-module)
dea4d055 304(defun make-builtin-module ()
ea578bb4
MW
305 "Construct the builtin module.
306
9ec578d9
MW
307 This involves constructing the braid (which is done in
308 `bootstrap-classes') and defining a few obvious type names which users
309 will find handy.
ea578bb4
MW
310
311 Returns the newly constructed module, and stores it in the variable
312 `*builtin-module*'."
dea4d055
MW
313 (let ((module (make-instance 'module
314 :name (make-pathname :name "SOD-BASE"
315 :type "SOD"
316 :case :common)
ea578bb4 317 :state nil)))
9ec578d9
MW
318 (with-module-environment (module)
319 (dolist (name '("va_list" "size_t" "ptrdiff_t"))
320 (add-to-module module (make-instance 'type-item :name name)))
321 (flet ((header-name (name)
322 (concatenate 'string "\"" (string-downcase name) ".h\""))
323 (add-includes (reason &rest names)
324 (let ((text (with-output-to-string (out)
325 (dolist (name names)
326 (format out "#include ~A~%" name)))))
327 (add-to-module module
328 (make-instance 'code-fragment-item
329 :reason reason
330 :constraints nil
331 :name :includes
332 :fragment text)))))
333 (add-includes :c (header-name "sod"))
334 (add-includes :h "<stddef.h>"))
335 (bootstrap-classes module))
ea578bb4 336 (setf *builtin-module* module)))
dea4d055 337
54c01772
MW
338(define-clear-the-decks builtin-module
339 (unless *builtin-module* (make-builtin-module)))
340
dea4d055 341;;;----- That's all, folks --------------------------------------------------