* objects.c (scm_init_objects): Initialize destructor slot of the
[bpt/guile.git] / libguile / objects.c
1 /* Copyright (C) 1995,1996 Free Software Foundation, Inc.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2, or (at your option)
6 * any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this software; see the file COPYING. If not, write to
15 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
16 * Boston, MA 02111-1307 USA
17 *
18 * As a special exception, the Free Software Foundation gives permission
19 * for additional uses of the text contained in its release of GUILE.
20 *
21 * The exception is that, if you link the GUILE library with other files
22 * to produce an executable, this does not by itself cause the
23 * resulting executable to be covered by the GNU General Public License.
24 * Your use of that executable is in no way restricted on account of
25 * linking the GUILE library code into it.
26 *
27 * This exception does not however invalidate any other reasons why
28 * the executable file might be covered by the GNU General Public License.
29 *
30 * This exception applies only to the code released by the
31 * Free Software Foundation under the name GUILE. If you copy
32 * code from other Free Software Foundation releases into a copy of
33 * GUILE, as the General Public License permits, the exception does
34 * not apply to the code that you add in this way. To avoid misleading
35 * anyone as to the status of such modified files, you must delete
36 * this exception notice from them.
37 *
38 * If you write modifications of your own for GUILE, it is your choice
39 * whether to permit this exception to apply to your modifications.
40 * If you do not wish that, delete this exception notice. */
41 \f
42
43 /* This file and objects.h contains those minimal pieces of the Guile
44 * Object Oriented Programming System which need to be included in
45 * libguile. See the comments in objects.h.
46 */
47
48 #include "_scm.h"
49
50 #include "struct.h"
51 #include "procprop.h"
52 #include "chars.h"
53 #include "keywords.h"
54 #include "smob.h"
55
56 #include "objects.h"
57 \f
58
59 SCM scm_metaclass_standard;
60 SCM scm_metaclass_operator;
61
62 /* These variables are filled in by the object system when loaded. */
63 SCM scm_class_boolean, scm_class_char, scm_class_pair;
64 SCM scm_class_procedure, scm_class_string, scm_class_symbol;
65 SCM scm_class_procedure_with_setter;
66 SCM scm_class_vector, scm_class_null;
67 SCM scm_class_integer, scm_class_real, scm_class_complex;
68 SCM scm_class_unknown;
69
70 SCM *scm_smob_class = 0;
71
72 SCM (*scm_make_extended_class) (char *type_name);
73 void (*scm_change_object_class) (SCM, SCM, SCM);
74
75 /* This function is used for efficient type dispatch. */
76 SCM
77 scm_class_of (SCM x)
78 {
79 switch (SCM_ITAG3 (x))
80 {
81 case scm_tc3_int_1:
82 case scm_tc3_int_2:
83 return scm_class_integer;
84
85 case scm_tc3_imm24:
86 if (SCM_ICHRP (x))
87 return scm_class_char;
88 else
89 {
90 switch (SCM_ISYMNUM (x))
91 {
92 case SCM_ISYMNUM (SCM_BOOL_F):
93 case SCM_ISYMNUM (SCM_BOOL_T):
94 return scm_class_boolean;
95 case SCM_ISYMNUM (SCM_EOL):
96 return scm_class_null;
97 default:
98 return scm_class_unknown;
99 }
100 }
101
102 case scm_tc3_cons:
103 switch (SCM_TYP7 (x))
104 {
105 case scm_tcs_cons_nimcar:
106 return scm_class_pair;
107 case scm_tcs_closures:
108 return scm_class_procedure;
109 case scm_tcs_symbols:
110 return scm_class_symbol;
111 case scm_tc7_vector:
112 case scm_tc7_wvect:
113 case scm_tc7_bvect:
114 case scm_tc7_byvect:
115 case scm_tc7_svect:
116 case scm_tc7_ivect:
117 case scm_tc7_uvect:
118 case scm_tc7_fvect:
119 case scm_tc7_dvect:
120 case scm_tc7_cvect:
121 return scm_class_vector;
122 case scm_tc7_string:
123 case scm_tc7_substring:
124 return scm_class_string;
125 case scm_tc7_asubr:
126 case scm_tc7_subr_0:
127 case scm_tc7_subr_1:
128 case scm_tc7_cxr:
129 case scm_tc7_subr_3:
130 case scm_tc7_subr_2:
131 case scm_tc7_rpsubr:
132 case scm_tc7_subr_1o:
133 case scm_tc7_subr_2o:
134 case scm_tc7_lsubr_2:
135 case scm_tc7_lsubr:
136 case scm_tc7_cclo:
137 return scm_class_procedure;
138 case scm_tc7_pws:
139 return scm_class_procedure_with_setter;
140
141 case scm_tc7_port:
142 return scm_class_unknown;
143 case scm_tc7_smob:
144 {
145 SCM type = SCM_TYP16 (x);
146 if (type == scm_tc16_flo)
147 {
148 if (SCM_CAR (x) & SCM_IMAG_PART)
149 return scm_class_complex;
150 else
151 return scm_class_real;
152 }
153 else
154 return scm_smob_class[SCM_TC2SMOBNUM (type)];
155 }
156 case scm_tcs_cons_gloc:
157 /* must be a struct */
158 if (SCM_OBJ_CLASS_FLAGS (x) & SCM_CLASSF_GOOPS)
159 {
160 /* Goops object */
161 if (SCM_OBJ_CLASS_REDEF (x) != SCM_BOOL_F)
162 scm_change_object_class (x,
163 SCM_CLASS_OF (x), /* old */
164 SCM_OBJ_CLASS_REDEF (x)); /* new */
165 return SCM_CLASS_OF (x);
166 }
167 else
168 {
169 /* ordinary struct */
170 SCM handle = scm_struct_create_handle (SCM_STRUCT_VTABLE (x));
171 if (SCM_NFALSEP (SCM_STRUCT_TABLE_CLASS (SCM_CDR (handle))))
172 return SCM_STRUCT_TABLE_CLASS (SCM_CDR (handle));
173 else
174 {
175 SCM name = SCM_STRUCT_TABLE_NAME (SCM_CDR (handle));
176 SCM class = scm_make_extended_class (SCM_NFALSEP (name)
177 ? SCM_ROCHARS (name)
178 : 0);
179 SCM_SET_STRUCT_TABLE_CLASS (handle, class);
180 return class;
181 }
182 }
183 default:
184 if (SCM_CONSP (x))
185 return scm_class_pair;
186 else
187 return scm_class_unknown;
188 }
189
190 case scm_tc3_cons_gloc:
191 case scm_tc3_tc7_1:
192 case scm_tc3_tc7_2:
193 case scm_tc3_closure:
194 /* Never reached */
195 break;
196 }
197 return scm_class_unknown;
198 }
199
200 SCM_PROC (s_entity_p, "entity?", 1, 0, 0, scm_entity_p);
201
202 SCM
203 scm_entity_p (SCM obj)
204 {
205 return (SCM_NIMP (obj) && SCM_STRUCTP (obj) && SCM_I_ENTITYP (obj)
206 ? SCM_BOOL_T
207 : SCM_BOOL_F);
208 }
209
210 SCM_PROC (s_set_object_procedure_x, "set-object-procedure!", 1, 0, 1, scm_set_object_procedure_x);
211
212 SCM
213 scm_set_object_procedure_x (SCM obj, SCM procs)
214 {
215 SCM proc[4], *pp, p, setp, arity;
216 int i, a, r;
217 SCM_ASSERT (SCM_NIMP (obj) && SCM_STRUCTP (obj)
218 && ((SCM_CLASS_FLAGS (obj) & SCM_CLASSF_OPERATOR)
219 || SCM_I_ENTITYP (obj)),
220 obj,
221 SCM_ARG1,
222 s_set_object_procedure_x);
223 for (i = 0; i < 4; ++i)
224 proc[i] = SCM_BOOL_F;
225 i = 0;
226 while (SCM_NIMP (procs))
227 {
228 if (i == 4)
229 scm_wrong_num_args (scm_makfrom0str (s_set_object_procedure_x));
230 p = SCM_CAR (procs);
231 setp = 0;
232 SCM_ASSERT (SCM_NIMP (p), p, SCM_ARG2 + i, s_set_object_procedure_x);
233 if (SCM_CLOSUREP (p))
234 {
235 arity = scm_procedure_property (p, scm_sym_arity);
236 a = SCM_INUM (SCM_CAR (arity));
237 /* Closures have zero optional args */
238 r = SCM_NFALSEP (SCM_CADDR (arity));
239 if (a == 1 || (a <= 1 && r))
240 {
241 if (SCM_NFALSEP (proc[0]))
242 goto ambiguous;
243 proc[0] = setp = p;
244 }
245 if (a == 2 || (a <= 2 && r))
246 {
247 if (SCM_NFALSEP (proc[1]))
248 goto ambiguous;
249 proc[1] = setp = p;
250 }
251 if (a == 3 || (a <= 3 && r))
252 {
253 if (SCM_NFALSEP (proc[2]))
254 goto ambiguous;
255 proc[2] = setp = p;
256 }
257 if (a <= 4 && r)
258 {
259 if (SCM_NFALSEP (proc[3]))
260 goto ambiguous;
261 proc[3] = setp = p;
262 }
263 }
264 else if (SCM_TYP7 (p) == scm_tc7_subr_1)
265 {
266 if (SCM_NFALSEP (proc[0]))
267 goto ambiguous;
268 proc[0] = setp = p;
269 }
270 else if (SCM_TYP7 (p) == scm_tc7_subr_2)
271 {
272 if (SCM_NFALSEP (proc[1]))
273 goto ambiguous;
274 proc[1] = setp = p;
275 }
276 else if (SCM_TYP7 (p) == scm_tc7_subr_3)
277 {
278 if (SCM_NFALSEP (proc[2]))
279 goto ambiguous;
280 proc[2] = setp = p;
281 }
282 else if (SCM_TYP7 (p) == scm_tc7_lsubr_2)
283 {
284 if (SCM_NFALSEP (proc[3]))
285 {
286 ambiguous:
287 SCM_ASSERT (0, p, "Ambiguous procedure arities",
288 s_set_object_procedure_x);
289 }
290 proc[3] = setp = p;
291 }
292 SCM_ASSERT (setp, p, SCM_ARG2 + i, s_set_object_procedure_x);
293 ++i;
294 procs = SCM_CDR (procs);
295 }
296 pp = (SCM_I_ENTITYP (obj)
297 ? &SCM_ENTITY_PROC_0 (obj)
298 : &SCM_OPERATOR_CLASS (obj)->proc0);
299 for (i = 0; i < 4; ++i)
300 *pp++ = proc[i];
301 return SCM_UNSPECIFIED;
302 }
303
304 /* The following procedures are not a part of Goops but a minimal
305 * object system built upon structs. They are here for those who
306 * want to implement their own object system.
307 */
308
309 SCM
310 scm_i_make_class_object (SCM meta,
311 SCM layout_string,
312 unsigned long flags)
313 {
314 SCM c;
315 SCM layout = scm_make_struct_layout (layout_string);
316 c = scm_make_struct (meta,
317 SCM_INUM0,
318 SCM_LIST4 (layout, SCM_BOOL_F, SCM_EOL, SCM_EOL));
319 SCM_SET_CLASS_FLAGS (c, flags);
320 return c;
321 }
322
323 SCM_PROC (s_make_class_object, "make-class-object", 2, 0, 0, scm_make_class_object);
324
325 SCM
326 scm_make_class_object (SCM metaclass, SCM layout)
327 {
328 unsigned long flags = 0;
329 SCM_ASSERT (SCM_NIMP (metaclass) && SCM_STRUCTP (metaclass),
330 metaclass, SCM_ARG1, s_make_class_object);
331 SCM_ASSERT (SCM_NIMP (layout) && SCM_STRINGP (layout),
332 layout, SCM_ARG2, s_make_class_object);
333 if (metaclass == scm_metaclass_operator)
334 flags = SCM_CLASSF_OPERATOR;
335 return scm_i_make_class_object (metaclass, layout, flags);
336 }
337
338 SCM_PROC (s_make_subclass_object, "make-subclass-object", 2, 0, 0, scm_make_subclass_object);
339
340 SCM
341 scm_make_subclass_object (SCM class, SCM layout)
342 {
343 SCM pl;
344 SCM_ASSERT (SCM_NIMP (class) && SCM_STRUCTP (class),
345 class,
346 SCM_ARG1,
347 s_make_subclass_object);
348 SCM_ASSERT (SCM_NIMP (layout) && SCM_STRINGP (layout),
349 layout,
350 SCM_ARG2,
351 s_make_subclass_object);
352 pl = SCM_STRUCT_DATA (class)[scm_vtable_index_layout];
353 /* Convert symbol->string */
354 pl = scm_makfromstr (SCM_CHARS (pl), (scm_sizet) SCM_LENGTH (pl), 0);
355 return scm_i_make_class_object (SCM_STRUCT_VTABLE (class),
356 scm_string_append (SCM_LIST2 (pl, layout)),
357 SCM_CLASS_FLAGS (class));
358 }
359
360 void
361 scm_init_objects ()
362 {
363 SCM ms = scm_makfrom0str (SCM_METACLASS_STANDARD_LAYOUT);
364 SCM ml = scm_make_struct_layout (ms);
365 SCM mt = scm_make_vtable_vtable (ml, SCM_INUM0,
366 SCM_LIST3 (SCM_BOOL_F, SCM_EOL, SCM_EOL));
367
368 SCM os = scm_makfrom0str (SCM_METACLASS_OPERATOR_LAYOUT);
369 SCM ol = scm_make_struct_layout (os);
370 SCM ot = scm_make_vtable_vtable (ol, SCM_INUM0,
371 SCM_LIST3 (SCM_BOOL_F, SCM_EOL, SCM_EOL));
372
373 SCM es = scm_makfrom0str (SCM_ENTITY_LAYOUT);
374 SCM el = scm_make_struct_layout (es);
375 SCM et = scm_make_struct (mt, SCM_INUM0,
376 SCM_LIST4 (el, SCM_BOOL_F, SCM_EOL, SCM_EOL));
377
378 scm_sysintern ("<class>", mt);
379 scm_metaclass_standard = mt;
380 scm_sysintern ("<operator-class>", ot);
381 scm_metaclass_operator = ot;
382 SCM_SET_CLASS_FLAGS (et, SCM_CLASSF_OPERATOR | SCM_CLASSF_ENTITY);
383 SCM_SET_CLASS_DESTRUCTOR (et, scm_struct_free_entity);
384 scm_sysintern ("<entity>", et);
385
386 #include "objects.x"
387 }