An actual running implementation, which makes code that compiles.
[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)
64 (make-property-set :lisp-class 'sod-class-slot
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
ea578bb4 98 ~:{sod__obj->~A.~A._vt = &~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)
108 (vtable-name class head))))
109 (ilayout-ichains ilayout)))))
110
111(define-class-slot "init" (class stream)
112 (* (fun (* void) ("/*p*/" (* void))))
113 (format nil "~A__init" class)
114
115 ;; FIXME this needs a metaobject protocol
ea578bb4
MW
116 (let ((ilayout (sod-class-ilayout class))
117 (used nil))
dea4d055 118 (format stream "~&~:
ea578bb4
MW
119/* Provide initial values for an instance's slots. */
120static void *~A__init(void *p)~%{~%" class)
dea4d055 121 (dolist (ichain (ilayout-ichains ilayout))
ea578bb4 122 (let ((ich (format nil "sod__obj->~A.~A"
dea4d055
MW
123 (sod-class-nickname (ichain-head ichain))
124 (sod-class-nickname (ichain-tail ichain)))))
125 (dolist (item (ichain-body ichain))
126 (etypecase item
127 (vtable-pointer
128 nil)
129 (islots
130 (let ((isl (format nil "~A.~A"
131 ich
132 (sod-class-nickname (islots-class item)))))
133 (dolist (slot (islots-slots item))
134 (let ((dslot (effective-slot-direct-slot slot))
135 (init (effective-slot-initializer slot)))
136 (when init
ea578bb4
MW
137 (unless used
138 (format stream
9ec578d9
MW
139 " struct ~A *sod__obj = ~A__imprint(p);~2%"
140 (ilayout-struct-tag class) class)
ea578bb4 141 (setf used t))
dea4d055
MW
142 (format stream " ~A.~A =" isl
143 (sod-slot-name dslot))
144 (ecase (sod-initializer-value-kind init)
145 (:simple (write (sod-initializer-value-form init)
146 :stream stream
147 :pretty nil :escape nil)
148 (format stream ";~%"))
149 (:compound (format stream " (~A) {"
150 (sod-slot-type dslot))
151 (write (sod-initializer-value-form init)
152 :stream stream
153 :pretty nil :escape nil)
154 (format stream "};~%"))))))))))))
ea578bb4
MW
155 (unless used
156 (format stream " ~A__imprint(p);~%" class))
dea4d055
MW
157 (format stream "~&~:
158 return (p);
159}~2%")))
160
161;;;--------------------------------------------------------------------------
162;;; Superclass structure.
163
164(define-class-slot "n_supers" (class) size-t
165 (length (sod-class-direct-superclasses class)))
166
167(define-class-slot "supers" (class stream)
168 (* (* (class "SodClass" :const) :const))
169 (if (null (sod-class-direct-superclasses class)) 0
170 (format nil "~A__supers" class))
171 (let ((supers (sod-class-direct-superclasses class)))
172 (when supers
173 (format stream "~&~:
174/* Direct superclasses. */
175static const SodClass *const ~A__supers[] = {
176 ~{~A__class~^,~% ~}
177};~2%"
178 class supers))))
179
180(define-class-slot "n_cpl" (class) size-t
181 (length (sod-class-precedence-list class)))
182
183(define-class-slot "cpl" (class stream)
184 (* (* (class "SodClass" :const) :const))
185 (format nil "~A__cpl" class)
186 (format stream "~&~:
187/* Class precedence list. */
188static const SodClass *const ~A__cpl[] = {
189 ~{~A__class~^,~% ~}
190};~2%"
191 class (sod-class-precedence-list class)))
192
193;;;--------------------------------------------------------------------------
194;;; Chain structure.
195
196(define-class-slot "link" (class) (* (class "SodClass" :const))
197 (aif (sod-class-chain-link class)
198 (format nil "~A__class" it)
199 0))
200
201(define-class-slot "head" (class) (* (class "SodClass" :const))
202 (format nil "~A__class" (sod-class-chain-head class)))
203
204(define-class-slot "level" (class) size-t
205 (position class (reverse (sod-class-chain class))))
206
207(define-class-slot "n_chains" (class) size-t
208 (length (sod-class-chains class)))
209
210(define-class-slot "chains" (class stream) (* (struct "sod_chain" :const))
211 (format nil "~A__chains" class)
212 (let ((chains (sod-class-chains class)))
213 (format stream "~&~:
214/* Chain structure. */
215~1@*~:{static const SodClass *const ~A__chain_~A[] = {
216 ~{~A__class~^,~% ~}
217};~:^~2%~}
218
219~0@*static const struct sod_chain ~A__chains[] = {
9ec578d9
MW
220~:{ { ~
221 /* n_classes = */ ~3@*~A,
222 /* classes = */ ~0@*~A__chain_~A,
223 /* off_ichain = */ ~4@*offsetof(struct ~A, ~A),
224 /* vt = */ (const struct sod_vtable *)&~A,
225 /* ichainsz = */ sizeof(struct ~A) }~:^,~%~}
dea4d055
MW
226};~2%"
227 class ;0
228 (mapcar (lambda (chain) ;1
229 (let* ((head (sod-class-chain-head (car chain)))
9ec578d9 230 (tail (sod-class-chain-head (car chain)))
dea4d055 231 (chain-nick (sod-class-nickname head)))
9ec578d9
MW
232 (list class chain-nick ;0 1
233 (reverse chain) ;2
234 (length chain) ;3
235 (ilayout-struct-tag class) chain-nick ;4 5
236 (vtable-name class head) ;6
237 (ichain-struct-tag (car chain) head)))) ;7
dea4d055
MW
238 chains))))
239
240;;;--------------------------------------------------------------------------
241;;; Class-specific layout.
242
243(define-class-slot "off_islots" (class) size-t
9ec578d9
MW
244 (if (sod-class-slots class)
245 (format nil "offsetof(struct ~A, ~A)"
246 (ichain-struct-tag class (sod-class-chain-head class))
247 (sod-class-nickname class))
248 "0"))
dea4d055
MW
249
250(define-class-slot "islotsz" (class) size-t
9ec578d9
MW
251 (if (sod-class-slots class)
252 (format nil "sizeof(struct ~A)"
253 (islots-struct-tag class))
254 "0"))
dea4d055
MW
255
256;;;--------------------------------------------------------------------------
257;;; Bootstrapping the class graph.
258
259(defun bootstrap-classes (module)
ea578bb4
MW
260 "Bootstrap the braid in MODULE.
261
262 This builds the fundamental recursive braid, where `SodObject' is an
263 instance of `SodClass', and `SodClass' is a subclass of `SodObject' (and
264 an instance of itself)."
dea4d055
MW
265 (let* ((sod-object (make-sod-class "SodObject" nil
266 (make-property-set :nick 'obj)))
267 (sod-class (make-sod-class "SodClass" (list sod-object)
268 (make-property-set :nick 'cls)))
269 (classes (list sod-object sod-class)))
270
271 ;; Sort out the recursion.
272 (setf (slot-value sod-class 'chain-link) sod-object)
273 (dolist (class classes)
274 (setf (slot-value class 'metaclass) sod-class))
275
276 ;; Predeclare the class types.
277 (dolist (class classes)
278 (make-class-type (sod-class-name class)))
279
280 ;; Attach the class slots.
281 (dolist (slot *class-slot-alist*)
282 (funcall (cdr slot) sod-class))
283
284 ;; These classes are too closely intertwined. We must partially finalize
285 ;; them together by hand. This is cloned from `finalize-sod-class'.
286 (dolist (class classes)
287 (with-slots (class-precedence-list chain-head chain chains) class
288 (setf class-precedence-list (compute-cpl class))
289 (setf (values chain-head chain chains) (compute-chains class))))
290
291 ;; Done.
292 (dolist (class classes)
293 (finalize-sod-class class)
294 (add-to-module module class))))
295
ea578bb4
MW
296(defvar *builtin-module* nil
297 "The builtin module.")
298
dea4d055 299(defun make-builtin-module ()
ea578bb4
MW
300 "Construct the builtin module.
301
9ec578d9
MW
302 This involves constructing the braid (which is done in
303 `bootstrap-classes') and defining a few obvious type names which users
304 will find handy.
ea578bb4
MW
305
306 Returns the newly constructed module, and stores it in the variable
307 `*builtin-module*'."
dea4d055
MW
308 (let ((module (make-instance 'module
309 :name (make-pathname :name "SOD-BASE"
310 :type "SOD"
311 :case :common)
ea578bb4 312 :state nil)))
9ec578d9
MW
313 (with-module-environment (module)
314 (dolist (name '("va_list" "size_t" "ptrdiff_t"))
315 (add-to-module module (make-instance 'type-item :name name)))
316 (flet ((header-name (name)
317 (concatenate 'string "\"" (string-downcase name) ".h\""))
318 (add-includes (reason &rest names)
319 (let ((text (with-output-to-string (out)
320 (dolist (name names)
321 (format out "#include ~A~%" name)))))
322 (add-to-module module
323 (make-instance 'code-fragment-item
324 :reason reason
325 :constraints nil
326 :name :includes
327 :fragment text)))))
328 (add-includes :c (header-name "sod"))
329 (add-includes :h "<stddef.h>"))
330 (bootstrap-classes module))
ea578bb4 331 (setf *builtin-module* module)))
dea4d055
MW
332
333;;;----- That's all, folks --------------------------------------------------