*** empty log message ***
[bpt/guile.git] / libguile / objects.c
1 /* Copyright (C) 1995,1996,1999,2000,2001, 2003 Free Software Foundation, Inc.
2 *
3 * This library is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Lesser General Public
5 * License as published by the Free Software Foundation; either
6 * version 2.1 of the License, or (at your option) any later version.
7 *
8 * This library 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 GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with this library; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 */
17
18
19 \f
20
21 /* This file and objects.h contains those minimal pieces of the Guile
22 * Object Oriented Programming System which need to be included in
23 * libguile. See the comments in objects.h.
24 */
25
26 #include "libguile/_scm.h"
27
28 #include "libguile/struct.h"
29 #include "libguile/procprop.h"
30 #include "libguile/chars.h"
31 #include "libguile/keywords.h"
32 #include "libguile/smob.h"
33 #include "libguile/eval.h"
34 #include "libguile/alist.h"
35 #include "libguile/ports.h"
36 #include "libguile/strings.h"
37 #include "libguile/vectors.h"
38
39 #include "libguile/validate.h"
40 #include "libguile/objects.h"
41 \f
42
43 SCM scm_metaclass_standard;
44 SCM scm_metaclass_operator;
45
46 /* These variables are filled in by the object system when loaded. */
47 SCM scm_class_boolean, scm_class_char, scm_class_pair;
48 SCM scm_class_procedure, scm_class_string, scm_class_symbol;
49 SCM scm_class_procedure_with_setter, scm_class_primitive_generic;
50 SCM scm_class_vector, scm_class_null;
51 SCM scm_class_integer, scm_class_real, scm_class_complex;
52 SCM scm_class_unknown;
53
54 SCM *scm_port_class = 0;
55 SCM *scm_smob_class = 0;
56
57 SCM scm_no_applicable_method;
58
59 /* This function is used for efficient type dispatch. */
60 SCM_DEFINE (scm_class_of, "class-of", 1, 0, 0,
61 (SCM x),
62 "Return the class of @var{x}.")
63 #define FUNC_NAME s_scm_class_of
64 {
65 switch (SCM_ITAG3 (x))
66 {
67 case scm_tc3_int_1:
68 case scm_tc3_int_2:
69 return scm_class_integer;
70
71 case scm_tc3_imm24:
72 if (SCM_CHARP (x))
73 return scm_class_char;
74 else
75 {
76 switch (SCM_ISYMNUM (x))
77 {
78 case SCM_ISYMNUM (SCM_BOOL_F):
79 case SCM_ISYMNUM (SCM_BOOL_T):
80 return scm_class_boolean;
81 case SCM_ISYMNUM (SCM_EOL):
82 return scm_class_null;
83 default:
84 return scm_class_unknown;
85 }
86 }
87
88 case scm_tc3_cons:
89 switch (SCM_TYP7 (x))
90 {
91 case scm_tcs_cons_nimcar:
92 return scm_class_pair;
93 case scm_tcs_closures:
94 return scm_class_procedure;
95 case scm_tc7_symbol:
96 return scm_class_symbol;
97 case scm_tc7_vector:
98 case scm_tc7_wvect:
99 #if SCM_HAVE_ARRAYS
100 case scm_tc7_bvect:
101 case scm_tc7_byvect:
102 case scm_tc7_svect:
103 case scm_tc7_ivect:
104 case scm_tc7_uvect:
105 case scm_tc7_fvect:
106 case scm_tc7_dvect:
107 case scm_tc7_cvect:
108 #endif
109 return scm_class_vector;
110 case scm_tc7_string:
111 return scm_class_string;
112 case scm_tc7_asubr:
113 case scm_tc7_subr_0:
114 case scm_tc7_subr_1:
115 case scm_tc7_cxr:
116 case scm_tc7_subr_3:
117 case scm_tc7_subr_2:
118 case scm_tc7_rpsubr:
119 case scm_tc7_subr_1o:
120 case scm_tc7_subr_2o:
121 case scm_tc7_lsubr_2:
122 case scm_tc7_lsubr:
123 if (SCM_SUBR_GENERIC (x) && *SCM_SUBR_GENERIC (x))
124 return scm_class_primitive_generic;
125 else
126 return scm_class_procedure;
127 case scm_tc7_cclo:
128 return scm_class_procedure;
129 case scm_tc7_pws:
130 return scm_class_procedure_with_setter;
131
132 case scm_tc7_smob:
133 {
134 scm_t_bits type = SCM_TYP16 (x);
135 if (type != scm_tc16_port_with_ps)
136 return scm_smob_class[SCM_TC2SMOBNUM (type)];
137 x = SCM_PORT_WITH_PS_PORT (x);
138 /* fall through to ports */
139 }
140 case scm_tc7_port:
141 return scm_port_class[(SCM_WRTNG & SCM_CELL_WORD_0 (x)
142 ? (SCM_RDNG & SCM_CELL_WORD_0 (x)
143 ? SCM_INOUT_PCLASS_INDEX | SCM_PTOBNUM (x)
144 : SCM_OUT_PCLASS_INDEX | SCM_PTOBNUM (x))
145 : SCM_IN_PCLASS_INDEX | SCM_PTOBNUM (x))];
146 case scm_tcs_struct:
147 if (SCM_OBJ_CLASS_FLAGS (x) & SCM_CLASSF_GOOPS_VALID)
148 return SCM_CLASS_OF (x);
149 else if (SCM_OBJ_CLASS_FLAGS (x) & SCM_CLASSF_GOOPS)
150 {
151 /* Goops object */
152 if (! SCM_FALSEP (SCM_OBJ_CLASS_REDEF (x)))
153 scm_change_object_class (x,
154 SCM_CLASS_OF (x), /* old */
155 SCM_OBJ_CLASS_REDEF (x)); /* new */
156 return SCM_CLASS_OF (x);
157 }
158 else
159 {
160 /* ordinary struct */
161 SCM handle = scm_struct_create_handle (SCM_STRUCT_VTABLE (x));
162 if (!SCM_FALSEP (SCM_STRUCT_TABLE_CLASS (SCM_CDR (handle))))
163 return SCM_STRUCT_TABLE_CLASS (SCM_CDR (handle));
164 else
165 {
166 SCM name = SCM_STRUCT_TABLE_NAME (SCM_CDR (handle));
167 SCM class = scm_make_extended_class (!SCM_FALSEP (name)
168 ? SCM_SYMBOL_CHARS (name)
169 : 0,
170 SCM_I_OPERATORP (x));
171 SCM_SET_STRUCT_TABLE_CLASS (SCM_CDR (handle), class);
172 return class;
173 }
174 }
175 default:
176 if (SCM_CONSP (x))
177 return scm_class_pair;
178 else
179 return scm_class_unknown;
180 }
181
182 case scm_tc3_struct:
183 case scm_tc3_tc7_1:
184 case scm_tc3_tc7_2:
185 case scm_tc3_closure:
186 /* Never reached */
187 break;
188 }
189 return scm_class_unknown;
190 }
191 #undef FUNC_NAME
192
193 /* The cache argument for scm_mcache_lookup_cmethod has one of two possible
194 * formats:
195 *
196 * Format #1:
197 * (SCM_IM_DISPATCH ARGS N-SPECIALIZED
198 * #((TYPE1 ... ENV FORMALS FORM ...) ...)
199 * GF)
200 *
201 * Format #2:
202 * (SCM_IM_HASH_DISPATCH ARGS N-SPECIALIZED HASHSET MASK
203 * #((TYPE1 ... ENV FORMALS FORM ...) ...)
204 * GF)
205 *
206 * ARGS is either a list of expressions, in which case they
207 * are interpreted as the arguments of an application, or
208 * a non-pair, which is interpreted as a single expression
209 * yielding all arguments.
210 *
211 * SCM_IM_DISPATCH expressions in generic functions always
212 * have ARGS = the symbol `args' or the iloc #@0-0.
213 *
214 * Need FORMALS in order to support varying arity. This
215 * also avoids the need for renaming of bindings.
216 *
217 * We should probably not complicate this mechanism by
218 * introducing "optimizations" for getters and setters or
219 * primitive methods. Getters and setter will normally be
220 * compiled into @slot-[ref|set!] or a procedure call.
221 * They rely on the dispatch performed before executing
222 * the code which contains them.
223 *
224 * We might want to use a more efficient representation of
225 * this form in the future, perhaps after we have introduced
226 * low-level support for syntax-case macros.
227 */
228
229 SCM
230 scm_mcache_lookup_cmethod (SCM cache, SCM args)
231 {
232 long i, n, end, mask;
233 SCM ls, methods, z = SCM_CDDR (cache);
234 n = SCM_INUM (SCM_CAR (z)); /* maximum number of specializers */
235 methods = SCM_CADR (z);
236
237 if (SCM_INUMP (methods))
238 {
239 /* cache format #2: compute a hash value */
240 long hashset = SCM_INUM (methods);
241 long j = n;
242 z = SCM_CDDR (z);
243 mask = SCM_INUM (SCM_CAR (z));
244 methods = SCM_CADR (z);
245 i = 0;
246 ls = args;
247 if (!SCM_NULLP (ls))
248 do
249 {
250 i += SCM_STRUCT_DATA (scm_class_of (SCM_CAR (ls)))
251 [scm_si_hashsets + hashset];
252 ls = SCM_CDR (ls);
253 }
254 while (j-- && !SCM_NULLP (ls));
255 i &= mask;
256 end = i;
257 }
258 else /* SCM_VECTORP (methods) */
259 {
260 /* cache format #1: prepare for linear search */
261 mask = -1;
262 i = 0;
263 end = SCM_VECTOR_LENGTH (methods);
264 }
265
266 /* Search for match */
267 do
268 {
269 long j = n;
270 z = SCM_VELTS (methods)[i];
271 ls = args; /* list of arguments */
272 if (!SCM_NULLP (ls))
273 do
274 {
275 /* More arguments than specifiers => CLASS != ENV */
276 if (! SCM_EQ_P (scm_class_of (SCM_CAR (ls)), SCM_CAR (z)))
277 goto next_method;
278 ls = SCM_CDR (ls);
279 z = SCM_CDR (z);
280 }
281 while (j-- && !SCM_NULLP (ls));
282 /* Fewer arguments than specifiers => CAR != ENV */
283 if (SCM_NULLP (SCM_CAR (z)) || SCM_CONSP (SCM_CAR (z)))
284 return z;
285 next_method:
286 i = (i + 1) & mask;
287 } while (i != end);
288 return SCM_BOOL_F;
289 }
290
291 SCM
292 scm_mcache_compute_cmethod (SCM cache, SCM args)
293 {
294 SCM cmethod = scm_mcache_lookup_cmethod (cache, args);
295 if (SCM_FALSEP (cmethod))
296 /* No match - memoize */
297 return scm_memoize_method (cache, args);
298 return cmethod;
299 }
300
301 SCM
302 scm_apply_generic (SCM gf, SCM args)
303 {
304 SCM cmethod = scm_mcache_compute_cmethod (SCM_ENTITY_PROCEDURE (gf), args);
305 return scm_eval_body (SCM_CDR (SCM_CMETHOD_CODE (cmethod)),
306 SCM_EXTEND_ENV (SCM_CAR (SCM_CMETHOD_CODE (cmethod)),
307 args,
308 SCM_CMETHOD_ENV (cmethod)));
309 }
310
311 SCM
312 scm_call_generic_0 (SCM gf)
313 {
314 return scm_apply_generic (gf, SCM_EOL);
315 }
316
317 SCM
318 scm_call_generic_1 (SCM gf, SCM a1)
319 {
320 return scm_apply_generic (gf, scm_list_1 (a1));
321 }
322
323 SCM
324 scm_call_generic_2 (SCM gf, SCM a1, SCM a2)
325 {
326 return scm_apply_generic (gf, scm_list_2 (a1, a2));
327 }
328
329 SCM
330 scm_call_generic_3 (SCM gf, SCM a1, SCM a2, SCM a3)
331 {
332 return scm_apply_generic (gf, scm_list_3 (a1, a2, a3));
333 }
334
335 SCM_DEFINE (scm_entity_p, "entity?", 1, 0, 0,
336 (SCM obj),
337 "Return @code{#t} if @var{obj} is an entity.")
338 #define FUNC_NAME s_scm_entity_p
339 {
340 return SCM_BOOL(SCM_STRUCTP (obj) && SCM_I_ENTITYP (obj));
341 }
342 #undef FUNC_NAME
343
344 SCM_DEFINE (scm_operator_p, "operator?", 1, 0, 0,
345 (SCM obj),
346 "Return @code{#t} if @var{obj} is an operator.")
347 #define FUNC_NAME s_scm_operator_p
348 {
349 return SCM_BOOL(SCM_STRUCTP (obj)
350 && SCM_I_OPERATORP (obj)
351 && !SCM_I_ENTITYP (obj));
352 }
353 #undef FUNC_NAME
354
355 /* XXX - What code requires the object procedure to be only of certain
356 types? */
357
358 SCM_DEFINE (scm_valid_object_procedure_p, "valid-object-procedure?", 1, 0, 0,
359 (SCM proc),
360 "Return @code{#t} iff @var{proc} is a procedure that can be used "
361 "with @code{set-object-procedure}. It is always valid to use "
362 "a closure constructed by @code{lambda}.")
363 #define FUNC_NAME s_scm_valid_object_procedure_p
364 {
365 if (SCM_IMP (proc))
366 return SCM_BOOL_F;
367 switch (SCM_TYP7 (proc))
368 {
369 default:
370 return SCM_BOOL_F;
371 case scm_tcs_closures:
372 case scm_tc7_subr_1:
373 case scm_tc7_subr_2:
374 case scm_tc7_subr_3:
375 case scm_tc7_lsubr_2:
376 return SCM_BOOL_T;
377 }
378 }
379 #undef FUNC_NAME
380
381 SCM_DEFINE (scm_set_object_procedure_x, "set-object-procedure!", 2, 0, 0,
382 (SCM obj, SCM proc),
383 "Set the object procedure of @var{obj} to @var{proc}.\n"
384 "@var{obj} must be either an entity or an operator.")
385 #define FUNC_NAME s_scm_set_object_procedure_x
386 {
387 SCM_ASSERT (SCM_STRUCTP (obj)
388 && ((SCM_CLASS_FLAGS (obj) & SCM_CLASSF_OPERATOR)
389 || (SCM_I_ENTITYP (obj)
390 && !(SCM_OBJ_CLASS_FLAGS (obj)
391 & SCM_CLASSF_PURE_GENERIC))),
392 obj,
393 SCM_ARG1,
394 FUNC_NAME);
395 SCM_ASSERT (scm_valid_object_procedure_p (proc), proc, SCM_ARG2, FUNC_NAME);
396 if (SCM_I_ENTITYP (obj))
397 SCM_SET_ENTITY_PROCEDURE (obj, proc);
398 else
399 SCM_OPERATOR_CLASS (obj)->procedure = proc;
400 return SCM_UNSPECIFIED;
401 }
402 #undef FUNC_NAME
403
404 #ifdef GUILE_DEBUG
405 SCM_DEFINE (scm_object_procedure, "object-procedure", 1, 0, 0,
406 (SCM obj),
407 "Return the object procedure of @var{obj}. @var{obj} must be\n"
408 "an entity or an operator.")
409 #define FUNC_NAME s_scm_object_procedure
410 {
411 SCM_ASSERT (SCM_STRUCTP (obj)
412 && ((SCM_CLASS_FLAGS (obj) & SCM_CLASSF_OPERATOR)
413 || SCM_I_ENTITYP (obj)),
414 obj, SCM_ARG1, FUNC_NAME);
415 return (SCM_I_ENTITYP (obj)
416 ? SCM_ENTITY_PROCEDURE (obj)
417 : SCM_OPERATOR_CLASS (obj)->procedure);
418 }
419 #undef FUNC_NAME
420 #endif /* GUILE_DEBUG */
421
422 /* The following procedures are not a part of Goops but a minimal
423 * object system built upon structs. They are here for those who
424 * want to implement their own object system.
425 */
426
427 SCM
428 scm_i_make_class_object (SCM meta,
429 SCM layout_string,
430 unsigned long flags)
431 {
432 SCM c;
433 SCM layout = scm_make_struct_layout (layout_string);
434 c = scm_make_struct (meta,
435 SCM_INUM0,
436 scm_list_4 (layout, SCM_BOOL_F, SCM_EOL, SCM_EOL));
437 SCM_SET_CLASS_FLAGS (c, flags);
438 return c;
439 }
440
441 SCM_DEFINE (scm_make_class_object, "make-class-object", 2, 0, 0,
442 (SCM metaclass, SCM layout),
443 "Create a new class object of class @var{metaclass}, with the\n"
444 "slot layout specified by @var{layout}.")
445 #define FUNC_NAME s_scm_make_class_object
446 {
447 unsigned long flags = 0;
448 SCM_VALIDATE_STRUCT (1, metaclass);
449 SCM_VALIDATE_STRING (2, layout);
450 if (SCM_EQ_P (metaclass, scm_metaclass_operator))
451 flags = SCM_CLASSF_OPERATOR;
452 return scm_i_make_class_object (metaclass, layout, flags);
453 }
454 #undef FUNC_NAME
455
456 SCM_DEFINE (scm_make_subclass_object, "make-subclass-object", 2, 0, 0,
457 (SCM class, SCM layout),
458 "Create a subclass object of @var{class}, with the slot layout\n"
459 "specified by @var{layout}.")
460 #define FUNC_NAME s_scm_make_subclass_object
461 {
462 SCM pl;
463 SCM_VALIDATE_STRUCT (1, class);
464 SCM_VALIDATE_STRING (2, layout);
465 pl = SCM_PACK (SCM_STRUCT_DATA (class) [scm_vtable_index_layout]);
466 /* Convert symbol->string */
467 pl = scm_mem2string (SCM_SYMBOL_CHARS (pl), SCM_SYMBOL_LENGTH (pl));
468 return scm_i_make_class_object (SCM_STRUCT_VTABLE (class),
469 scm_string_append (scm_list_2 (pl, layout)),
470 SCM_CLASS_FLAGS (class));
471 }
472 #undef FUNC_NAME
473
474 void
475 scm_init_objects ()
476 {
477 SCM ms = scm_makfrom0str (SCM_METACLASS_STANDARD_LAYOUT);
478 SCM mt = scm_make_vtable_vtable (ms, SCM_INUM0,
479 scm_list_3 (SCM_BOOL_F, SCM_EOL, SCM_EOL));
480
481 SCM os = scm_makfrom0str (SCM_METACLASS_OPERATOR_LAYOUT);
482 SCM ot = scm_make_vtable_vtable (os, SCM_INUM0,
483 scm_list_3 (SCM_BOOL_F, SCM_EOL, SCM_EOL));
484
485 SCM es = scm_makfrom0str (SCM_ENTITY_LAYOUT);
486 SCM el = scm_make_struct_layout (es);
487 SCM et = scm_make_struct (mt, SCM_INUM0,
488 scm_list_4 (el, SCM_BOOL_F, SCM_EOL, SCM_EOL));
489
490 scm_c_define ("<class>", mt);
491 scm_metaclass_standard = mt;
492 scm_c_define ("<operator-class>", ot);
493 scm_metaclass_operator = ot;
494 SCM_SET_CLASS_FLAGS (et, SCM_CLASSF_OPERATOR | SCM_CLASSF_ENTITY);
495 SCM_SET_CLASS_DESTRUCTOR (et, scm_struct_free_entity);
496 scm_c_define ("<entity>", et);
497
498 #include "libguile/objects.x"
499 }
500
501 /*
502 Local Variables:
503 c-file-style: "gnu"
504 End:
505 */