~peter-pearse/ubuntu/natty/guile-1.8/prop001

« back to all changes in this revision

Viewing changes to libguile/objects.c

  • Committer: Bazaar Package Importer
  • Author(s): Daniel Schepler
  • Date: 2006-11-09 03:11:16 UTC
  • Revision ID: james.westby@ubuntu.com-20061109031116-hu0q1jxqg12y6yeg
Tags: upstream-1.8.1+1
ImportĀ upstreamĀ versionĀ 1.8.1+1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (C) 1995,1996,1999,2000,2001, 2003, 2004, 2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
16
 */
 
17
 
 
18
 
 
19
 
 
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
#include "libguile/goops.h"
 
42
 
 
43
 
 
44
 
 
45
SCM scm_metaclass_standard;
 
46
SCM scm_metaclass_operator;
 
47
 
 
48
/* The cache argument for scm_mcache_lookup_cmethod has one of two possible
 
49
 * formats:
 
50
 *
 
51
 * Format #1:
 
52
 * (SCM_IM_DISPATCH ARGS N-SPECIALIZED
 
53
 *   #((TYPE1 ... ENV FORMALS FORM ...) ...)
 
54
 *   GF)
 
55
 *
 
56
 * Format #2:
 
57
 * (SCM_IM_HASH_DISPATCH ARGS N-SPECIALIZED HASHSET MASK
 
58
 *   #((TYPE1 ... ENV FORMALS FORM ...) ...)
 
59
 *   GF)
 
60
 *
 
61
 * ARGS is either a list of expressions, in which case they
 
62
 * are interpreted as the arguments of an application, or
 
63
 * a non-pair, which is interpreted as a single expression
 
64
 * yielding all arguments.
 
65
 *
 
66
 * SCM_IM_DISPATCH expressions in generic functions always
 
67
 * have ARGS = the symbol `args' or the iloc #@0-0.
 
68
 *
 
69
 * Need FORMALS in order to support varying arity.  This
 
70
 * also avoids the need for renaming of bindings.
 
71
 *
 
72
 * We should probably not complicate this mechanism by
 
73
 * introducing "optimizations" for getters and setters or
 
74
 * primitive methods.  Getters and setter will normally be
 
75
 * compiled into @slot-[ref|set!] or a procedure call.
 
76
 * They rely on the dispatch performed before executing
 
77
 * the code which contains them.
 
78
 *
 
79
 * We might want to use a more efficient representation of
 
80
 * this form in the future, perhaps after we have introduced
 
81
 * low-level support for syntax-case macros.
 
82
 */
 
83
 
 
84
SCM
 
85
scm_mcache_lookup_cmethod (SCM cache, SCM args)
 
86
{
 
87
  unsigned long i, mask, n, end;
 
88
  SCM ls, methods, z = SCM_CDDR (cache);
 
89
  n = scm_to_ulong (SCM_CAR (z)); /* maximum number of specializers */
 
90
  methods = SCM_CADR (z);
 
91
 
 
92
  if (scm_is_simple_vector (methods))
 
93
    {
 
94
      /* cache format #1: prepare for linear search */
 
95
      mask = -1;
 
96
      i = 0;
 
97
      end = SCM_SIMPLE_VECTOR_LENGTH (methods);
 
98
    }
 
99
  else
 
100
    {
 
101
      /* cache format #2: compute a hash value */
 
102
      unsigned long hashset = scm_to_ulong (methods);
 
103
      long j = n;
 
104
      z = SCM_CDDR (z);
 
105
      mask = scm_to_ulong (SCM_CAR (z));
 
106
      methods = SCM_CADR (z);
 
107
      i = 0;
 
108
      ls = args;
 
109
      if (!scm_is_null (ls))
 
110
        do
 
111
          {
 
112
            i += SCM_STRUCT_DATA (scm_class_of (SCM_CAR (ls)))
 
113
                 [scm_si_hashsets + hashset];
 
114
            ls = SCM_CDR (ls);
 
115
          }
 
116
        while (j-- && !scm_is_null (ls));
 
117
      i &= mask;
 
118
      end = i;
 
119
    }
 
120
 
 
121
  /* Search for match  */
 
122
  do
 
123
    {
 
124
      long j = n;
 
125
      z = SCM_SIMPLE_VECTOR_REF (methods, i);
 
126
      ls = args; /* list of arguments */
 
127
      if (!scm_is_null (ls))
 
128
        do
 
129
          {
 
130
            /* More arguments than specifiers => CLASS != ENV */
 
131
            if (! scm_is_eq (scm_class_of (SCM_CAR (ls)), SCM_CAR (z)))
 
132
              goto next_method;
 
133
            ls = SCM_CDR (ls);
 
134
            z = SCM_CDR (z);
 
135
          }
 
136
        while (j-- && !scm_is_null (ls));
 
137
      /* Fewer arguments than specifiers => CAR != ENV */
 
138
      if (scm_is_null (SCM_CAR (z)) || scm_is_pair (SCM_CAR (z)))
 
139
        return z;
 
140
    next_method:
 
141
      i = (i + 1) & mask;
 
142
    } while (i != end);
 
143
  return SCM_BOOL_F;
 
144
}
 
145
 
 
146
SCM
 
147
scm_mcache_compute_cmethod (SCM cache, SCM args)
 
148
{
 
149
  SCM cmethod = scm_mcache_lookup_cmethod (cache, args);
 
150
  if (scm_is_false (cmethod))
 
151
    /* No match - memoize */
 
152
    return scm_memoize_method (cache, args);
 
153
  return cmethod;
 
154
}
 
155
 
 
156
SCM
 
157
scm_apply_generic (SCM gf, SCM args)
 
158
{
 
159
  SCM cmethod = scm_mcache_compute_cmethod (SCM_ENTITY_PROCEDURE (gf), args);
 
160
  return scm_eval_body (SCM_CDR (SCM_CMETHOD_CODE (cmethod)),
 
161
                        SCM_EXTEND_ENV (SCM_CAR (SCM_CMETHOD_CODE (cmethod)),
 
162
                                        args,
 
163
                                        SCM_CMETHOD_ENV (cmethod)));
 
164
}
 
165
 
 
166
SCM
 
167
scm_call_generic_0 (SCM gf)
 
168
{
 
169
  return scm_apply_generic (gf, SCM_EOL);
 
170
}
 
171
 
 
172
SCM
 
173
scm_call_generic_1 (SCM gf, SCM a1)
 
174
{
 
175
  return scm_apply_generic (gf, scm_list_1 (a1));
 
176
}
 
177
 
 
178
SCM
 
179
scm_call_generic_2 (SCM gf, SCM a1, SCM a2)
 
180
{
 
181
  return scm_apply_generic (gf, scm_list_2 (a1, a2));
 
182
}
 
183
 
 
184
SCM
 
185
scm_call_generic_3 (SCM gf, SCM a1, SCM a2, SCM a3)
 
186
{
 
187
  return scm_apply_generic (gf, scm_list_3 (a1, a2, a3));
 
188
}
 
189
 
 
190
SCM_DEFINE (scm_entity_p, "entity?", 1, 0, 0, 
 
191
            (SCM obj),
 
192
            "Return @code{#t} if @var{obj} is an entity.")
 
193
#define FUNC_NAME s_scm_entity_p
 
194
{
 
195
  return scm_from_bool(SCM_STRUCTP (obj) && SCM_I_ENTITYP (obj));
 
196
}
 
197
#undef FUNC_NAME
 
198
 
 
199
SCM_DEFINE (scm_operator_p, "operator?", 1, 0, 0, 
 
200
            (SCM obj),
 
201
            "Return @code{#t} if @var{obj} is an operator.")
 
202
#define FUNC_NAME s_scm_operator_p
 
203
{
 
204
  return scm_from_bool(SCM_STRUCTP (obj)
 
205
                  && SCM_I_OPERATORP (obj)
 
206
                  && !SCM_I_ENTITYP (obj));
 
207
}
 
208
#undef FUNC_NAME
 
209
 
 
210
/* XXX - What code requires the object procedure to be only of certain
 
211
         types? */
 
212
 
 
213
SCM_DEFINE (scm_valid_object_procedure_p, "valid-object-procedure?", 1, 0, 0,
 
214
            (SCM proc),
 
215
            "Return @code{#t} iff @var{proc} is a procedure that can be used "
 
216
            "with @code{set-object-procedure}.  It is always valid to use "
 
217
            "a closure constructed by @code{lambda}.")
 
218
#define FUNC_NAME s_scm_valid_object_procedure_p
 
219
{
 
220
  if (SCM_IMP (proc))
 
221
    return SCM_BOOL_F;
 
222
  switch (SCM_TYP7 (proc))
 
223
    {
 
224
    default:
 
225
      return SCM_BOOL_F;
 
226
    case scm_tcs_closures:
 
227
    case scm_tc7_subr_1:
 
228
    case scm_tc7_subr_2:
 
229
    case scm_tc7_subr_3:
 
230
    case scm_tc7_lsubr_2:
 
231
      return SCM_BOOL_T;
 
232
    }
 
233
}
 
234
#undef FUNC_NAME
 
235
 
 
236
SCM_DEFINE (scm_set_object_procedure_x, "set-object-procedure!", 2, 0, 0, 
 
237
            (SCM obj, SCM proc),
 
238
            "Set the object procedure of @var{obj} to @var{proc}.\n"
 
239
            "@var{obj} must be either an entity or an operator.")
 
240
#define FUNC_NAME s_scm_set_object_procedure_x
 
241
{
 
242
  SCM_ASSERT (SCM_STRUCTP (obj)
 
243
              && ((SCM_CLASS_FLAGS (obj) & SCM_CLASSF_OPERATOR)
 
244
                  || (SCM_I_ENTITYP (obj)
 
245
                      && !(SCM_OBJ_CLASS_FLAGS (obj)
 
246
                           & SCM_CLASSF_PURE_GENERIC))),
 
247
              obj,
 
248
              SCM_ARG1,
 
249
              FUNC_NAME);
 
250
  SCM_ASSERT (scm_valid_object_procedure_p (proc), proc, SCM_ARG2, FUNC_NAME);
 
251
  if (SCM_I_ENTITYP (obj))
 
252
    SCM_SET_ENTITY_PROCEDURE (obj, proc);
 
253
  else
 
254
    SCM_OPERATOR_CLASS (obj)->procedure = proc;
 
255
  return SCM_UNSPECIFIED;
 
256
}
 
257
#undef FUNC_NAME
 
258
 
 
259
#ifdef GUILE_DEBUG
 
260
SCM_DEFINE (scm_object_procedure, "object-procedure", 1, 0, 0, 
 
261
            (SCM obj),
 
262
            "Return the object procedure of @var{obj}. @var{obj} must be\n"
 
263
            "an entity or an operator.")
 
264
#define FUNC_NAME s_scm_object_procedure
 
265
{
 
266
  SCM_ASSERT (SCM_STRUCTP (obj)
 
267
              && ((SCM_CLASS_FLAGS (obj) & SCM_CLASSF_OPERATOR)
 
268
                  || SCM_I_ENTITYP (obj)),
 
269
              obj, SCM_ARG1, FUNC_NAME);
 
270
  return (SCM_I_ENTITYP (obj)
 
271
          ? SCM_ENTITY_PROCEDURE (obj)
 
272
          : SCM_OPERATOR_CLASS (obj)->procedure);
 
273
}
 
274
#undef FUNC_NAME
 
275
#endif /* GUILE_DEBUG */
 
276
 
 
277
/* The following procedures are not a part of Goops but a minimal
 
278
 * object system built upon structs.  They are here for those who
 
279
 * want to implement their own object system.
 
280
 */
 
281
 
 
282
SCM
 
283
scm_i_make_class_object (SCM meta,
 
284
                         SCM layout_string,
 
285
                         unsigned long flags)
 
286
{
 
287
  SCM c;
 
288
  SCM layout = scm_make_struct_layout (layout_string);
 
289
  c = scm_make_struct (meta,
 
290
                       SCM_INUM0,
 
291
                       scm_list_4 (layout, SCM_BOOL_F, SCM_EOL, SCM_EOL));
 
292
  SCM_SET_CLASS_FLAGS (c, flags);
 
293
  return c;
 
294
}
 
295
 
 
296
SCM_DEFINE (scm_make_class_object, "make-class-object", 2, 0, 0, 
 
297
            (SCM metaclass, SCM layout),
 
298
            "Create a new class object of class @var{metaclass}, with the\n"
 
299
            "slot layout specified by @var{layout}.")
 
300
#define FUNC_NAME s_scm_make_class_object
 
301
{
 
302
  unsigned long flags = 0;
 
303
  SCM_VALIDATE_STRUCT (1, metaclass);
 
304
  SCM_VALIDATE_STRING (2, layout);
 
305
  if (scm_is_eq (metaclass, scm_metaclass_operator))
 
306
    flags = SCM_CLASSF_OPERATOR;
 
307
  return scm_i_make_class_object (metaclass, layout, flags);
 
308
}
 
309
#undef FUNC_NAME
 
310
 
 
311
SCM_DEFINE (scm_make_subclass_object, "make-subclass-object", 2, 0, 0, 
 
312
            (SCM class, SCM layout),
 
313
            "Create a subclass object of @var{class}, with the slot layout\n"
 
314
            "specified by @var{layout}.")
 
315
#define FUNC_NAME s_scm_make_subclass_object
 
316
{
 
317
  SCM pl;
 
318
  SCM_VALIDATE_STRUCT (1, class);
 
319
  SCM_VALIDATE_STRING (2, layout);
 
320
  pl = SCM_PACK (SCM_STRUCT_DATA (class) [scm_vtable_index_layout]);
 
321
  pl = scm_symbol_to_string (pl);
 
322
  return scm_i_make_class_object (SCM_STRUCT_VTABLE (class),
 
323
                                  scm_string_append (scm_list_2 (pl, layout)),
 
324
                                  SCM_CLASS_FLAGS (class));
 
325
}
 
326
#undef FUNC_NAME
 
327
 
 
328
void
 
329
scm_init_objects ()
 
330
{
 
331
  SCM ms = scm_from_locale_string (SCM_METACLASS_STANDARD_LAYOUT);
 
332
  SCM mt = scm_make_vtable_vtable (ms, SCM_INUM0,
 
333
                                   scm_list_3 (SCM_BOOL_F, SCM_EOL, SCM_EOL));
 
334
  
 
335
  SCM os = scm_from_locale_string (SCM_METACLASS_OPERATOR_LAYOUT);
 
336
  SCM ot = scm_make_vtable_vtable (os, SCM_INUM0,
 
337
                                   scm_list_3 (SCM_BOOL_F, SCM_EOL, SCM_EOL));
 
338
  
 
339
  SCM es = scm_from_locale_string (SCM_ENTITY_LAYOUT);
 
340
  SCM el = scm_make_struct_layout (es);
 
341
  SCM et = scm_make_struct (mt, SCM_INUM0,
 
342
                            scm_list_4 (el, SCM_BOOL_F, SCM_EOL, SCM_EOL));
 
343
 
 
344
  scm_c_define ("<class>", mt);
 
345
  scm_metaclass_standard = mt;
 
346
  scm_c_define ("<operator-class>", ot);
 
347
  scm_metaclass_operator = ot;
 
348
  SCM_SET_CLASS_FLAGS (et, SCM_CLASSF_OPERATOR | SCM_CLASSF_ENTITY);
 
349
  SCM_SET_CLASS_DESTRUCTOR (et, scm_struct_free_entity);
 
350
  scm_c_define ("<entity>", et);
 
351
 
 
352
#include "libguile/objects.x"
 
353
}
 
354
 
 
355
/*
 
356
  Local Variables:
 
357
  c-file-style: "gnu"
 
358
  End:
 
359
*/