It lives!
[sod] / builtin.lisp
CommitLineData
d9c15186
MW
1;;; -*-lisp-*-
2;;;
3;;; Builtin module provides basic definitions
4;;;
5;;; (c) 2009 Straylight/Edgeware
6;;;
7
8;;;----- Licensing notice ---------------------------------------------------
9;;;
10;;; This file is part of the Simple Object Definition system.
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;;; Output of class instances.
30
31(defun output-imprint-function (class stream)
32 (let ((ilayout (sod-class-ilayout class)))
33 (format stream "~&~:
3be8c2bf 34/* Imprint raw memory with instance structure. */
d9c15186
MW
35static void *~A__imprint(void *p)
36{
37 struct ~A *sod__obj = p;
38
3be8c2bf 39 ~:{sod__obj.~A.~A._vt = &~A;~:^~% ~}
d9c15186
MW
40 return (p);
41}~2%"
42 class
43 (ilayout-struct-tag class)
44 (mapcar (lambda (ichain)
3be8c2bf
MW
45 (let* ((head (ichain-head ichain))
46 (tail (ichain-tail ichain)))
47 (list (sod-class-nickname head)
48 (sod-class-nickname tail)
49 (vtable-name class head))))
d9c15186
MW
50 (ilayout-ichains ilayout)))))
51
52(defun output-init-function (class stream)
53 ;; FIXME this needs a metaobject protocol
54 (let ((ilayout (sod-class-ilayout class)))
55 (format stream "~&~:
56static void *~A__init(void *p)
57{
58 struct ~A *sod__obj = ~0@*~A__imprint(p);~2%"
59 class
60 (ilayout-struct-tag class))
61 (dolist (ichain (ilayout-ichains ilayout))
3be8c2bf
MW
62 (let ((ich (format nil "sod__obj.~A.~A"
63 (sod-class-nickname (ichain-head ichain))
64 (sod-class-nickname (ichain-tail ichain)))))
d9c15186
MW
65 (dolist (item (ichain-body ichain))
66 (etypecase item
67 (vtable-pointer
a07d8d00 68 nil)
d9c15186
MW
69 (islots
70 (let ((isl (format nil "~A.~A"
71 ich
72 (sod-class-nickname (islots-class item)))))
73 (dolist (slot (islots-slots item))
74 (let ((dslot (effective-slot-direct-slot slot))
75 (init (effective-slot-initializer slot)))
76 (when init
a07d8d00 77 (format stream " ~A =" isl)
d9c15186 78 (ecase (sod-initializer-value-kind init)
a07d8d00
MW
79 (:simple (write (sod-initializer-value-form init)
80 :stream stream
81 :pretty nil :escape nil)
82 (format stream ";~%"))
83 (:compound (format stream " (~A) {"
84 (sod-slot-type dslot))
85 (write (sod-initializer-value-form init)
86 :stream stream
87 :pretty nil :escape nil)
88 (format stream "};~%"))))))))))))
d9c15186
MW
89 (format stream "~&~:
90 return (p);
91}~2%")))
92
93(defun output-supers-vector (class stream)
94 (let ((supers (sod-class-direct-superclasses class)))
95 (when supers
96 (format stream "~&~:
3be8c2bf 97/* Direct superclasses. */
d9c15186
MW
98static const SodClass *const ~A__supers[] = {
99 ~{~A__class~^,~% ~}
100};~2%"
101 class supers))))
102
103(defun output-cpl-vector (class stream)
104 (format stream "~&~:
3be8c2bf 105/* Class precedence list. */
d9c15186
MW
106static const SodClass *const ~A__cpl[] = {
107 ~{~A__class~^,~% ~}
108};~2%"
109 class (sod-class-precedence-list class)))
110
111(defun output-chains-vector (class stream)
112 (let ((chains (sod-class-chains class)))
113 (format stream "~&~:
3be8c2bf 114/* Chain structure. */
d9c15186 115~1@*~:{static const SodClass *const ~A__chain_~A[] = {
3be8c2bf 116 ~{~A__class~^,~% ~}
d9c15186
MW
117};~:^~2%~}
118
119~0@*static const struct sod_chain ~A__chains[] = {
120~:{ { ~3@*~A,
121 ~0@*&~A__chain_~A,
122 ~4@*offsetof(struct ~A, ~A),
123 (const struct sod_vtable *)&~A,
124 sizeof(struct ~A) }~:^,~%~}
125};~2%"
126 class ;0
127 (mapcar (lambda (chain) ;1
128 (let* ((head (sod-class-chain-head (car chain)))
129 (chain-nick (sod-class-nickname head)))
130 (list class chain-nick ;0 1
131 (reverse chain) ;2
132 (length chain) ;3
133 (ilayout-struct-tag class) chain-nick ;4 5
134 (vtable-name class head) ;6
135 (ichain-struct-tag class head)))) ;7
136 chains))))
137
138(defclass sod-class-slot (sod-slot)
139 ((initializer-function :initarg :initializer-function
140 :type (or symbol function)
141 :reader sod-slot-initializer-function)
142 (prepare-function :initarg :prepare-function :type (or symbol function)
143 :reader sod-slot-prepare-function))
144 (:documentation
145 "Special class for slots defined on SodClass.
146
147 These slots need class-specific initialization. It's easier to keep all
148 of the information (name, type, and how to initialize them) about these
149 slots in one place, so that's what we do here."))
150
3be8c2bf
MW
151(defclass sod-magic-class-initializer (sod-class-initializer)
152 ((initializer-function :initarg :initializer-function
153 :type (or symbol function)
154 :reader sod-initializer-function)
155 (prepare-function :initarg :prepare-function
156 :type (or symbol function)
157 :reader sod-initializer-prepare-function)))
158
d9c15186
MW
159(defmethod shared-initialize :after
160 ((slot sod-class-slot) slot-names &key pset)
161 (declare (ignore slot-names))
162 (default-slot (slot 'initializer-function)
163 (get-property pset :initializer-function t nil))
164 (default-slot (slot 'prepare-function)
165 (get-property pset :prepare-function t nil)))
166
167(defclass sod-class-effective-slot (effective-slot)
168 ((initializer-function :initarg :initializer-function
169 :type (or symbol function)
170 :reader effective-slot-initializer-function)
171 (prepare-function :initarg :prepare-function :type (or symbol function)
172 :reader effective-slot-prepare-function))
173 (:documentation
174 "Special class for slots defined on SodClass.
175
176 This class ignores any explicit initializers and computes initializer
177 values using the slot's INIT-FUNC slot and a magical protocol during
178 metaclass instance construction."))
179
180(defmethod compute-effective-slot ((class sod-class) (slot sod-class-slot))
181 (make-instance 'sod-class-effective-slot
3be8c2bf 182 :class class :slot slot
d9c15186
MW
183 :initializer-function (sod-slot-initializer-function slot)
184 :prepare-function (sod-slot-prepare-function slot)
185 :initializer (find-slot-initializer class slot)))
186
187;;;--------------------------------------------------------------------------
188;;; Class slots table.
189
190(defparameter *sod-class-slots*
191 `(
192
193 ;; Basic informtion.
194 ("name" ,(c-type const-string)
195 :initializer-function
196 ,(lambda (class)
197 (prin1-to-string (sod-class-name class))))
198 ("nick" ,(c-type const-string)
199 :initializer-function
200 ,(lambda (class)
201 (prin1-to-string (sod-class-nickname class))))
202
203 ;; Instance allocation and initialization.
204 ("instsz" ,(c-type size-t)
205 :initializer-function
206 ,(lambda (class)
207 (format nil "sizeof(struct ~A)"
208 (ilayout-struct-tag class))))
ddee4bb1 209 ("imprint" ,(c-type (* (fun (* void) ("/*p*/" (* void)))))
3be8c2bf 210 :prepare-function output-imprint-function
d9c15186
MW
211 :initializer-function
212 ,(lambda (class)
213 (format nil "~A__imprint" class)))
ddee4bb1 214 ("init" ,(c-type (* (fun (* void) ("/*p*/" (* void)))))
3be8c2bf 215 :prepare-function output-init-function
d9c15186
MW
216 :initializer-function
217 ,(lambda (class)
218 (format nil "~A__init" class)))
219
220 ;; Superclass structure.
221 ("n_supers" ,(c-type size-t)
222 :initializer-function
223 ,(lambda (class)
224 (length (sod-class-direct-superclasses class))))
225 ("supers" ,(c-type (* (* (class "SodClass" :const) :const)))
3be8c2bf 226 :prepare-function output-supers-vector
d9c15186
MW
227 :initializer-function
228 ,(lambda (class)
229 (if (sod-class-direct-superclasses class)
230 (format nil "~A__supers" class)
231 0)))
232 ("n_cpl" ,(c-type size-t)
233 :initializer-function
234 ,(lambda (class)
235 (length (sod-class-precedence-list class))))
236 ("cpl" ,(c-type (* (* (class "SodClass" :const) :const)))
3be8c2bf 237 :prepare-function output-cpl-vector
d9c15186
MW
238 :initializer-function
239 ,(lambda (class)
240 (format nil "~A__cpl" class)))
241
242 ;; Chain structure.
243 ("link" ,(c-type (* (class "SodClass" :const)))
244 :initializer-function
245 ,(lambda (class)
246 (let ((link (sod-class-chain-link class)))
247 (if link
248 (format nil "~A__class" link)
249 0))))
250 ("head" ,(c-type (* (class "SodClass" :const)))
251 :initializer-function
252 ,(lambda (class)
253 (format nil "~A__class" (sod-class-chain-head class))))
254 ("level" ,(c-type size-t)
255 :initializer-function
256 ,(lambda (class)
257 (position class (reverse (sod-class-chain class)))))
258 ("n_chains" ,(c-type size-t)
259 :initializer-function
260 ,(lambda (class)
261 (length (sod-class-chains class))))
262 ("chains" ,(c-type (* (struct "sod_chain" :const)))
3be8c2bf 263 :prepare-function output-chains-vector
d9c15186
MW
264 :initializer-function
265 ,(lambda (class)
266 (format nil "~A__chains" class)))
267
268 ;; Class-specific layout.
269 ("off_islots" ,(c-type size-t)
270 :initializer-function
271 ,(lambda (class)
272 (format nil "offsetof(struct ~A, ~A)"
273 (ichain-struct-tag class
274 (sod-class-chain-head class))
275 (sod-class-nickname class))))
276 ("islotsz" ,(c-type size-t)
277 :initializer-function
278 ,(lambda (class)
279 (format nil "sizeof(struct ~A)"
280 (islots-struct-tag class))))))
281
282;;;--------------------------------------------------------------------------
283;;; Bootstrapping the class graph.
284
285(defun bootstrap-classes (module)
286 (let* ((sod-object (make-sod-class "SodObject" nil
287 (make-property-set :nick 'obj)))
288 (sod-class (make-sod-class "SodClass" (list sod-object)
289 (make-property-set :nick 'cls)))
290 (classes (list sod-object sod-class)))
291
292 ;; Sort out the recursion.
293 (setf (slot-value sod-class 'chain-link) sod-object)
294 (dolist (class classes)
295 (setf (slot-value class 'metaclass) sod-class))
296
297 ;; Predeclare the class types.
298 (dolist (class classes)
299 (make-class-type (sod-class-name class)))
300
301 ;; Attach the class slots.
302 (loop for (name type . plist) in *sod-class-slots*
303 do (make-sod-slot sod-class name type
304 (apply #'make-property-set
305 :lisp-class 'sod-class-slot
306 plist)))
307
308 ;; These classes are too closely intertwined. We must partially finalize
309 ;; them together by hand. This is cloned from FINALIZE-SOD-CLASS.
310 (dolist (class classes)
311 (with-slots (class-precedence-list chain-head chain chains) class
312 (setf class-precedence-list (compute-cpl class))
313 (setf (values chain-head chain chains) (compute-chains class))))
314
315 ;; Done.
316 (dolist (class classes)
317 (finalize-sod-class class)
318 (add-to-module module class))))
319
320(defun make-builtin-module ()
321 (let ((module (make-instance 'module
ddee4bb1 322 :name (make-pathname :name "SOD-BASE"
d9c15186
MW
323 :type "SOD"
324 :case :common)
325 :state nil))
326 (*type-map* (make-hash-table :test #'equal)))
327 (dolist (name '("va_list" "size_t" "ptrdiff_t"))
328 (add-to-module module (make-instance 'type-item :name name)))
329 (bootstrap-classes module)
330 module))
331
332(defun reset-builtin-module ()
333 (setf *builtin-module* (make-builtin-module))
334 (module-import *builtin-module*))
335
336;;;--------------------------------------------------------------------------
337;;; Testing.
338
339#+test
340(define-sod-class "AbstractStack" ("SodObject")
341 :nick 'abstk
342 (message "emptyp" (fun int))
343 (message "push" (fun void ("item" (* void))))
344 (message "pop" (fun (* void)))
345 (method "abstk" "pop" (fun void) #{
346 assert(!me->_vt.emptyp());
347 }
348 :role :before))
349
350;;;----- That's all, folks --------------------------------------------------