3 ;;; Builtin module provides the root of the class graph
5 ;;; (c) 2009 Straylight/Edgeware
8 ;;;----- Licensing notice ---------------------------------------------------
10 ;;; This file is part of the Sensble Object Design, an object system for C.
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.
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.
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.
28 ;;;--------------------------------------------------------------------------
31 (defvar *class-slot-alist* nil)
33 (defun add-class-slot-function (name function)
34 "Attach a slot function to the *class-slot-alist*.
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.
41 Functions are are invoked in the order in which their names were first
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))))))
48 (defmacro define-class-slot
49 (name (class &optional stream) type init &body prepare)
50 "Define a new class slot.
52 The slot will be caled NAME, and will be of TYPE (which should be a type
53 S-expression). The slot's (static) initializer will be constructed by
54 printing the value of INIT, which is evaluated with CLASS bound to the
55 class object being constructed. If any PREPARE forms are provided, then
56 they are evaluated as a progn; they are evaluated with CLASS bound to the
57 class object, and STREAM bound to the output stream it should write on."
59 (with-gensyms (classvar)
60 `(add-class-slot-function
63 (make-sod-slot ,classvar ,name (c-type ,type)
64 (make-property-set :lisp-class 'sod-class-slot
70 (lambda (,class ,stream)
73 ;;;--------------------------------------------------------------------------
74 ;;; Basic information.
76 (define-class-slot "name" (class) const-string
77 (prin1-to-string (sod-class-name class)))
79 (define-class-slot "nick" (class) const-string
80 (prin1-to-string (sod-class-nickname class)))
82 ;;;--------------------------------------------------------------------------
83 ;;; Instance allocation and initialization.
85 (define-class-slot "initsz" (class) size-t
86 (format nil "sizeof(struct ~A)" (ilayout-struct-tag class)))
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)))
93 /* Imprint raw memory with instance structure. */
94 static void *~A__imprint(void *p)
96 struct ~A *sod__obj = p;
98 ~:{sod__obj.~A.~A._vt = &~A;~:^~% ~}
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)))))
111 (define-class-slot "init" (class stream)
112 (* (fun (* void) ("/*p*/" (* void))))
113 (format nil "~A__init" class)
115 ;; FIXME this needs a metaobject protocol
116 (let ((ilayout (sod-class-ilayout class)))
118 static void *~A__init(void *p)
120 struct ~A *sod__obj = ~0@*~A__imprint(p);~2%"
122 (ilayout-struct-tag class))
123 (dolist (ichain (ilayout-ichains ilayout))
124 (let ((ich (format nil "sod__obj.~A.~A"
125 (sod-class-nickname (ichain-head ichain))
126 (sod-class-nickname (ichain-tail ichain)))))
127 (dolist (item (ichain-body ichain))
132 (let ((isl (format nil "~A.~A"
134 (sod-class-nickname (islots-class item)))))
135 (dolist (slot (islots-slots item))
136 (let ((dslot (effective-slot-direct-slot slot))
137 (init (effective-slot-initializer slot)))
139 (format stream " ~A.~A =" isl
140 (sod-slot-name dslot))
141 (ecase (sod-initializer-value-kind init)
142 (:simple (write (sod-initializer-value-form init)
144 :pretty nil :escape nil)
145 (format stream ";~%"))
146 (:compound (format stream " (~A) {"
147 (sod-slot-type dslot))
148 (write (sod-initializer-value-form init)
150 :pretty nil :escape nil)
151 (format stream "};~%"))))))))))))
156 ;;;--------------------------------------------------------------------------
157 ;;; Superclass structure.
159 (define-class-slot "n_supers" (class) size-t
160 (length (sod-class-direct-superclasses class)))
162 (define-class-slot "supers" (class stream)
163 (* (* (class "SodClass" :const) :const))
164 (if (null (sod-class-direct-superclasses class)) 0
165 (format nil "~A__supers" class))
166 (let ((supers (sod-class-direct-superclasses class)))
169 /* Direct superclasses. */
170 static const SodClass *const ~A__supers[] = {
175 (define-class-slot "n_cpl" (class) size-t
176 (length (sod-class-precedence-list class)))
178 (define-class-slot "cpl" (class stream)
179 (* (* (class "SodClass" :const) :const))
180 (format nil "~A__cpl" class)
182 /* Class precedence list. */
183 static const SodClass *const ~A__cpl[] = {
186 class (sod-class-precedence-list class)))
188 ;;;--------------------------------------------------------------------------
191 (define-class-slot "link" (class) (* (class "SodClass" :const))
192 (aif (sod-class-chain-link class)
193 (format nil "~A__class" it)
196 (define-class-slot "head" (class) (* (class "SodClass" :const))
197 (format nil "~A__class" (sod-class-chain-head class)))
199 (define-class-slot "level" (class) size-t
200 (position class (reverse (sod-class-chain class))))
202 (define-class-slot "n_chains" (class) size-t
203 (length (sod-class-chains class)))
205 (define-class-slot "chains" (class stream) (* (struct "sod_chain" :const))
206 (format nil "~A__chains" class)
207 (let ((chains (sod-class-chains class)))
209 /* Chain structure. */
210 ~1@*~:{static const SodClass *const ~A__chain_~A[] = {
214 ~0@*static const struct sod_chain ~A__chains[] = {
217 ~4@*offsetof(struct ~A, ~A),
218 (const struct sod_vtable *)&~A,
219 sizeof(struct ~A) }~:^,~%~}
222 (mapcar (lambda (chain) ;1
223 (let* ((head (sod-class-chain-head (car chain)))
224 (chain-nick (sod-class-nickname head)))
225 (list class chain-nick ;0 1
228 (ilayout-struct-tag class) chain-nick ;4 5
229 (vtable-name class head) ;6
230 (ichain-struct-tag class head)))) ;7
233 ;;;--------------------------------------------------------------------------
234 ;;; Class-specific layout.
236 (define-class-slot "off_islots" (class) size-t
237 (format nil "offsetof(struct ~A, ~A)"
238 (ichain-struct-tag class (sod-class-chain-head class))
239 (sod-class-nickname class)))
241 (define-class-slot "islotsz" (class) size-t
242 (format nil "sizeof(struct ~A)"
243 (islots-struct-tag class)))
245 ;;;--------------------------------------------------------------------------
246 ;;; Bootstrapping the class graph.
248 (defun bootstrap-classes (module)
249 (let* ((sod-object (make-sod-class "SodObject" nil
250 (make-property-set :nick 'obj)))
251 (sod-class (make-sod-class "SodClass" (list sod-object)
252 (make-property-set :nick 'cls)))
253 (classes (list sod-object sod-class)))
255 ;; Sort out the recursion.
256 (setf (slot-value sod-class 'chain-link) sod-object)
257 (dolist (class classes)
258 (setf (slot-value class 'metaclass) sod-class))
260 ;; Predeclare the class types.
261 (dolist (class classes)
262 (make-class-type (sod-class-name class)))
264 ;; Attach the class slots.
265 (dolist (slot *class-slot-alist*)
266 (funcall (cdr slot) sod-class))
268 ;; These classes are too closely intertwined. We must partially finalize
269 ;; them together by hand. This is cloned from `finalize-sod-class'.
270 (dolist (class classes)
271 (with-slots (class-precedence-list chain-head chain chains) class
272 (setf class-precedence-list (compute-cpl class))
273 (setf (values chain-head chain chains) (compute-chains class))))
276 (dolist (class classes)
277 (finalize-sod-class class)
278 (add-to-module module class))))
280 (defun make-builtin-module ()
281 (let ((module (make-instance 'module
282 :name (make-pathname :name "SOD-BASE"
286 (include (format nil "#include \"~A\"~%"
287 (make-pathname :name "SOD" :type "H"
289 (call-with-module-environment
291 (dolist (name '("va_list" "size_t" "ptrdiff_t"))
292 (add-to-module module (make-instance 'type-item :name name)))
293 (add-to-module module (make-instance 'code-fragment-item
298 (bootstrap-classes module)))
301 (defvar *builtin-module* nil)
303 (define-clear-the-decks reset-builtin-module
304 (setf *builtin-module* (make-builtin-module)))
306 ;;;----- That's all, folks --------------------------------------------------