* vectors.c, symbols.c, strorder.c: Documentation cut and pasted
[bpt/guile.git] / libguile / symbols.c
1 /* Copyright (C) 1995,1996,1997,1998 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
42 /* Software engineering face-lift by Greg J. Badros, 11-Dec-1999,
43 gjb@cs.washington.edu, http://www.cs.washington.edu/homes/gjb */
44
45 \f
46
47 #include <stdio.h>
48 #include "_scm.h"
49 #include "chars.h"
50 #include "eval.h"
51 #include "variable.h"
52 #include "alist.h"
53 #include "weaks.h"
54
55 #include "scm_validate.h"
56 #include "symbols.h"
57
58 #ifdef HAVE_STRING_H
59 #include <string.h>
60 #endif
61
62 \f
63
64
65 /* NUM_HASH_BUCKETS is the number of symbol scm_hash table buckets.
66 */
67 #define NUM_HASH_BUCKETS 137
68
69 \f
70
71
72 /* {Symbols}
73 */
74
75
76 unsigned long
77 scm_strhash (unsigned char *str,scm_sizet len,unsigned long n)
78 {
79 if (len > 5)
80 {
81 scm_sizet i = 5;
82 unsigned long h = 264 % n;
83 while (i--)
84 h = ((h << 8) + ((unsigned) (scm_downcase (str[h % len])))) % n;
85 return h;
86 }
87 else
88 {
89 scm_sizet i = len;
90 unsigned long h = 0;
91 while (i)
92 h = ((h << 8) + ((unsigned) (scm_downcase (str[--i])))) % n;
93 return h;
94 }
95 }
96
97 int scm_symhash_dim = NUM_HASH_BUCKETS;
98
99
100 /* scm_sym2vcell
101 * looks up the symbol in the symhash table.
102 */
103
104 SCM
105 scm_sym2vcell (SCM sym,SCM thunk,SCM definep)
106 {
107 if (SCM_NIMP(thunk))
108 {
109 SCM var = scm_apply (thunk, sym, scm_cons(definep, scm_listofnull));
110
111 if (var == SCM_BOOL_F)
112 return SCM_BOOL_F;
113 else
114 {
115 if (SCM_IMP(var) || !SCM_VARIABLEP (var))
116 scm_wta (sym, "strangely interned symbol? ", "");
117 return SCM_VARVCELL (var);
118 }
119 }
120 else
121 {
122 SCM lsym;
123 SCM * lsymp;
124 SCM z;
125 scm_sizet scm_hash = scm_strhash (SCM_UCHARS (sym), (scm_sizet) SCM_LENGTH (sym),
126 (unsigned long) scm_symhash_dim);
127
128 SCM_DEFER_INTS;
129 for (lsym = SCM_VELTS (scm_symhash)[scm_hash]; SCM_NIMP (lsym); lsym = SCM_CDR (lsym))
130 {
131 z = SCM_CAR (lsym);
132 if (SCM_CAR (z) == sym)
133 {
134 SCM_ALLOW_INTS;
135 return z;
136 }
137 }
138
139 for (lsym = *(lsymp = &SCM_VELTS (scm_weak_symhash)[scm_hash]);
140 SCM_NIMP (lsym);
141 lsym = *(lsymp = SCM_CDRLOC (lsym)))
142 {
143 z = SCM_CAR (lsym);
144 if (SCM_CAR (z) == sym)
145 {
146 if (SCM_NFALSEP (definep))
147 {
148 /* Move handle from scm_weak_symhash to scm_symhash. */
149 *lsymp = SCM_CDR (lsym);
150 SCM_SETCDR (lsym, SCM_VELTS(scm_symhash)[scm_hash]);
151 SCM_VELTS(scm_symhash)[scm_hash] = lsym;
152 }
153 SCM_ALLOW_INTS;
154 return z;
155 }
156 }
157 SCM_ALLOW_INTS;
158 return scm_wta (sym, "uninterned symbol? ", "");
159 }
160 }
161
162 /* scm_sym2ovcell
163 * looks up the symbol in an arbitrary obarray.
164 */
165
166 SCM
167 scm_sym2ovcell_soft (SCM sym, SCM obarray)
168 {
169 SCM lsym, z;
170 scm_sizet scm_hash;
171
172 scm_hash = scm_strhash (SCM_UCHARS (sym),
173 (scm_sizet) SCM_LENGTH (sym),
174 SCM_LENGTH (obarray));
175 SCM_REDEFER_INTS;
176 for (lsym = SCM_VELTS (obarray)[scm_hash];
177 SCM_NIMP (lsym);
178 lsym = SCM_CDR (lsym))
179 {
180 z = SCM_CAR (lsym);
181 if (SCM_CAR (z) == sym)
182 {
183 SCM_REALLOW_INTS;
184 return z;
185 }
186 }
187 SCM_REALLOW_INTS;
188 return SCM_BOOL_F;
189 }
190
191
192 SCM
193 scm_sym2ovcell (SCM sym, SCM obarray)
194 {
195 SCM answer;
196 answer = scm_sym2ovcell_soft (sym, obarray);
197 if (answer != SCM_BOOL_F)
198 return answer;
199 scm_wta (sym, "uninterned symbol? ", "");
200 return SCM_UNSPECIFIED; /* not reached */
201 }
202
203 /* Intern a symbol whose name is the LEN characters at NAME in OBARRAY.
204
205 OBARRAY should be a vector of lists, indexed by the name's hash
206 value, modulo OBARRAY's length. Each list has the form
207 ((SYMBOL . VALUE) ...), where SYMBOL is a symbol, and VALUE is the
208 value associated with that symbol (in the current module? in the
209 system module?)
210
211 To "intern" a symbol means: if OBARRAY already contains a symbol by
212 that name, return its (SYMBOL . VALUE) pair; otherwise, create a
213 new symbol, add the pair (SYMBOL . SCM_UNDEFINED) to the
214 appropriate list of the OBARRAY, and return the pair.
215
216 If softness is non-zero, don't create a symbol if it isn't already
217 in OBARRAY; instead, just return #f.
218
219 If OBARRAY is SCM_BOOL_F, create a symbol listed in no obarray and
220 return (SYMBOL . SCM_UNDEFINED).
221
222 If OBARRAY is scm_symhash, and that doesn't contain the symbol,
223 check scm_weak_symhash instead. */
224
225
226 SCM
227 scm_intern_obarray_soft (const char *name,scm_sizet len,SCM obarray,int softness)
228 {
229 SCM lsym;
230 SCM z;
231 register scm_sizet i;
232 register unsigned char *tmp;
233 scm_sizet scm_hash;
234
235 SCM_REDEFER_INTS;
236
237 i = len;
238 tmp = (unsigned char *) name;
239
240 if (obarray == SCM_BOOL_F)
241 {
242 scm_hash = scm_strhash (tmp, i, 1019);
243 goto uninterned_symbol;
244 }
245
246 scm_hash = scm_strhash (tmp, i, SCM_LENGTH(obarray));
247
248 /* softness == -1 used to mean that it was known that the symbol
249 wasn't already in the obarray. I don't think there are any
250 callers that use that case any more, but just in case...
251 -- JimB, Oct 1996 */
252 if (softness == -1)
253 abort ();
254
255 retry_new_obarray:
256 for (lsym = SCM_VELTS (obarray)[scm_hash]; SCM_NIMP (lsym); lsym = SCM_CDR (lsym))
257 {
258 z = SCM_CAR (lsym);
259 z = SCM_CAR (z);
260 tmp = SCM_UCHARS (z);
261 if (SCM_LENGTH (z) != len)
262 goto trynext;
263 for (i = len; i--;)
264 if (((unsigned char *) name)[i] != tmp[i])
265 goto trynext;
266 {
267 SCM a;
268 a = SCM_CAR (lsym);
269 SCM_REALLOW_INTS;
270 return a;
271 }
272 trynext:;
273 }
274
275 if (obarray == scm_symhash)
276 {
277 obarray = scm_weak_symhash;
278 goto retry_new_obarray;
279 }
280
281 uninterned_symbol:
282 if (softness)
283 {
284 SCM_REALLOW_INTS;
285 return SCM_BOOL_F;
286 }
287
288 lsym = scm_makfromstr (name, len, SCM_SYMBOL_SLOTS);
289
290 SCM_SETLENGTH (lsym, (long) len, scm_tc7_msymbol);
291 SCM_SYMBOL_HASH (lsym) = scm_hash;
292 SCM_SYMBOL_PROPS (lsym) = SCM_EOL;
293 if (obarray == SCM_BOOL_F)
294 {
295 SCM answer;
296 SCM_REALLOW_INTS;
297 SCM_NEWCELL (answer);
298 SCM_DEFER_INTS;
299 SCM_SETCAR (answer, lsym);
300 SCM_SETCDR (answer, SCM_UNDEFINED);
301 SCM_REALLOW_INTS;
302 return answer;
303 }
304 else
305 {
306 SCM a;
307 SCM b;
308
309 SCM_NEWCELL (a);
310 SCM_NEWCELL (b);
311 SCM_SETCAR (a, lsym);
312 SCM_SETCDR (a, SCM_UNDEFINED);
313 SCM_SETCAR (b, a);
314 SCM_SETCDR (b, SCM_VELTS(obarray)[scm_hash]);
315 SCM_VELTS(obarray)[scm_hash] = b;
316 SCM_REALLOW_INTS;
317 return SCM_CAR (b);
318 }
319 }
320
321
322 SCM
323 scm_intern_obarray (const char *name,scm_sizet len,SCM obarray)
324 {
325 return scm_intern_obarray_soft (name, len, obarray, 0);
326 }
327
328
329 SCM
330 scm_intern (const char *name,scm_sizet len)
331 {
332 return scm_intern_obarray (name, len, scm_symhash);
333 }
334
335
336 SCM
337 scm_intern0 (const char * name)
338 {
339 return scm_intern (name, strlen (name));
340 }
341
342
343 /* Intern the symbol named NAME in scm_symhash, NAME is null-terminated. */
344 SCM
345 scm_sysintern0_no_module_lookup (const char *name)
346 {
347 SCM easy_answer;
348 SCM_DEFER_INTS;
349 easy_answer = scm_intern_obarray_soft (name, strlen (name), scm_symhash, 1);
350 if (SCM_NIMP (easy_answer))
351 {
352 SCM_ALLOW_INTS;
353 return easy_answer;
354 }
355 else
356 {
357 SCM lsym;
358 scm_sizet len = strlen (name);
359 register unsigned char *tmp = (unsigned char *) name;
360 scm_sizet scm_hash = scm_strhash (tmp, len, (unsigned long) scm_symhash_dim);
361 SCM_NEWCELL (lsym);
362 SCM_SETLENGTH (lsym, (long) len, scm_tc7_ssymbol);
363 SCM_SETCHARS (lsym, name);
364 lsym = scm_cons (lsym, SCM_UNDEFINED);
365 SCM_VELTS (scm_symhash)[scm_hash] = scm_cons (lsym, SCM_VELTS (scm_symhash)[scm_hash]);
366 SCM_ALLOW_INTS;
367 return lsym;
368 }
369 }
370
371
372 /* Is it safe to access SCM_TOP_LEVEL_LOOKUP_CLOSURE_VAR?
373 */
374 int scm_can_use_top_level_lookup_closure_var;
375
376 /* Intern the symbol named NAME in scm_symhash, and give it the value
377 VAL. NAME is null-terminated. Use the current top_level lookup
378 closure to give NAME its value.
379 */
380 SCM
381 scm_sysintern (const char *name, SCM val)
382 {
383 SCM vcell = scm_sysintern0 (name);
384 SCM_SETCDR (vcell, val);
385 return vcell;
386 }
387
388 SCM
389 scm_sysintern0 (const char *name)
390 {
391 SCM lookup_proc;
392 if (scm_can_use_top_level_lookup_closure_var &&
393 SCM_NIMP (lookup_proc = SCM_CDR (scm_top_level_lookup_closure_var)))
394 {
395 SCM sym = SCM_CAR (scm_intern0 (name));
396 SCM vcell = scm_sym2vcell (sym, lookup_proc, SCM_BOOL_T);
397 if (vcell == SCM_BOOL_F)
398 scm_misc_error ("sysintern0", "can't define variable", sym);
399 return vcell;
400 }
401 else
402 return scm_sysintern0_no_module_lookup (name);
403 }
404
405 /* Lookup the value of the symbol named by the nul-terminated string
406 NAME in the current module. */
407 SCM
408 scm_symbol_value0 (const char *name)
409 {
410 /* This looks silly - we look up the symbol twice. But it is in
411 fact necessary given the current module system because the module
412 lookup closures are written in scheme which needs real symbols. */
413 SCM symbol = scm_intern_obarray_soft (name, strlen (name), scm_symhash, 0);
414 SCM vcell = scm_sym2vcell (SCM_CAR (symbol),
415 SCM_CDR (scm_top_level_lookup_closure_var),
416 SCM_BOOL_F);
417 if (SCM_FALSEP (vcell))
418 return SCM_UNDEFINED;
419 return SCM_CDR (vcell);
420 }
421
422 SCM_DEFINE (scm_symbol_p, "symbol?", 1, 0, 0,
423 (SCM obj),
424 "Returns @t{#t} if @var{obj} is a symbol, otherwise returns @t{#f}. (r5rs)")
425 #define FUNC_NAME s_scm_symbol_p
426 {
427 if SCM_IMP(obj) return SCM_BOOL_F;
428 return SCM_BOOL(SCM_SYMBOLP(obj));
429 }
430 #undef FUNC_NAME
431
432 SCM_DEFINE (scm_symbol_to_string, "symbol->string", 1, 0, 0,
433 (SCM s),
434 "Returns the name of @var{symbol} as a string. If the symbol was part of\n"
435 "an object returned as the value of a literal expression\n"
436 "(section @pxref{Literal expressions}) or by a call to the @samp{read} procedure,\n"
437 "and its name contains alphabetic characters, then the string returned\n"
438 "will contain characters in the implementation's preferred standard\n"
439 "case---some implementations will prefer upper case, others lower case.\n"
440 "If the symbol was returned by @samp{string->symbol}, the case of\n"
441 "characters in the string returned will be the same as the case in the\n"
442 "string that was passed to @samp{string->symbol}. It is an error\n"
443 "to apply mutation procedures like @code{string-set!} to strings returned\n"
444 "by this procedure. (r5rs)\n\n"
445 "The following examples assume that the implementation's standard case is\n"
446 "lower case:\n\n"
447 "@format\n"
448 "@t{(symbol->string 'flying-fish) \n"
449 " ==> \"flying-fish\"\n"
450 "(symbol->string 'Martin) ==> \"martin\"\n"
451 "(symbol->string\n"
452 " (string->symbol "Malvina")) \n"
453 " ==> \"Malvina\"\n"
454 "}\n"
455 "@end format")
456 #define FUNC_NAME s_scm_symbol_to_string
457 {
458 SCM_VALIDATE_SYMBOL (1,s);
459 return scm_makfromstr(SCM_CHARS(s), (scm_sizet)SCM_LENGTH(s), 0);
460 }
461 #undef FUNC_NAME
462
463
464 SCM_DEFINE (scm_string_to_symbol, "string->symbol", 1, 0, 0,
465 (SCM s),
466 "Returns the symbol whose name is @var{string}. This procedure can\n"
467 "create symbols with names containing special characters or letters in\n"
468 "the non-standard case, but it is usually a bad idea to create such\n"
469 "symbols because in some implementations of Scheme they cannot be read as\n"
470 "themselves. See @samp{symbol->string}.\n\n"
471 "The following examples assume that the implementation's standard case is\n"
472 "lower case:\n\n"
473 "@format\n"
474 "@t{(eq? 'mISSISSIppi 'mississippi) \n"
475 " ==> #t\n"
476 "(string->symbol \"mISSISSIppi\") \n"
477 " ==>\n"
478 " @r{}the symbol with name \"mISSISSIppi\"\n"
479 "(eq? 'bitBlt (string->symbol \"bitBlt\")) \n"
480 " ==> #f\n"
481 "(eq? 'JollyWog\n"
482 " (string->symbol\n"
483 " (symbol->string 'JollyWog))) \n"
484 " ==> #t\n"
485 "(string=? \"K. Harper, M.D.\"\n"
486 " (symbol->string\n"
487 " (string->symbol \"K. Harper, M.D.\"))) \n"
488 " ==> #t\n"
489 "}\n"
490 "@end format")
491 #define FUNC_NAME s_scm_string_to_symbol
492 {
493 SCM vcell;
494 SCM answer;
495
496 SCM_VALIDATE_ROSTRING (1,s);
497 vcell = scm_intern(SCM_ROCHARS(s), (scm_sizet)SCM_LENGTH(s));
498 answer = SCM_CAR (vcell);
499 return answer;
500 }
501 #undef FUNC_NAME
502
503
504 SCM_DEFINE (scm_string_to_obarray_symbol, "string->obarray-symbol", 2, 1, 0,
505 (SCM o, SCM s, SCM softp),
506 "Intern a new symbol in @var{obarray}, a symbol table, with name\n"
507 "@var{string}.\n\n"
508 "If @var{obarray} is @code{#f}, use the default system symbol table. If\n"
509 "@var{obarray} is @code{#t}, the symbol should not be interned in any\n"
510 "symbol table; merely return the pair (@var{symbol}\n"
511 ". @var{#<undefined>}).\n\n"
512 "The @var{soft?} argument determines whether new symbol table entries\n"
513 "should be created when the specified symbol is not already present in\n"
514 "@var{obarray}. If @var{soft?} is specified and is a true value, then\n"
515 "new entries should not be added for symbols not already present in the\n"
516 "table; instead, simply return @code{#f}.")
517 #define FUNC_NAME s_scm_string_to_obarray_symbol
518 {
519 SCM vcell;
520 SCM answer;
521 int softness;
522
523 SCM_VALIDATE_ROSTRING (2,s);
524 SCM_ASSERT((o == SCM_BOOL_F)
525 || (o == SCM_BOOL_T)
526 || (SCM_VECTORP(o)),
527 o, SCM_ARG1, FUNC_NAME);
528
529 softness = ((softp != SCM_UNDEFINED) && (softp != SCM_BOOL_F));
530 /* iron out some screwy calling conventions */
531 if (o == SCM_BOOL_F)
532 o = scm_symhash;
533 else if (o == SCM_BOOL_T)
534 o = SCM_BOOL_F;
535
536 vcell = scm_intern_obarray_soft (SCM_ROCHARS(s),
537 (scm_sizet)SCM_ROLENGTH(s),
538 o,
539 softness);
540 if (vcell == SCM_BOOL_F)
541 return vcell;
542 answer = SCM_CAR (vcell);
543 return answer;
544 }
545 #undef FUNC_NAME
546
547 SCM_DEFINE (scm_intern_symbol, "intern-symbol", 2, 0, 0,
548 (SCM o, SCM s),
549 "Add a new symbol to @var{obarray} with name @var{string}, bound to an\n"
550 "unspecified initial value. The symbol table is not modified if a symbol\n"
551 "with this name is already present.")
552 #define FUNC_NAME s_scm_intern_symbol
553 {
554 scm_sizet hval;
555 SCM_VALIDATE_SYMBOL (2,s);
556 if (o == SCM_BOOL_F)
557 o = scm_symhash;
558 SCM_VALIDATE_VECTOR (1,o);
559 hval = scm_strhash (SCM_UCHARS (s), SCM_LENGTH (s), SCM_LENGTH(o));
560 /* If the symbol is already interned, simply return. */
561 SCM_REDEFER_INTS;
562 {
563 SCM lsym;
564 SCM sym;
565 for (lsym = SCM_VELTS (o)[hval];
566 SCM_NIMP (lsym);
567 lsym = SCM_CDR (lsym))
568 {
569 sym = SCM_CAR (lsym);
570 if (SCM_CAR (sym) == s)
571 {
572 SCM_REALLOW_INTS;
573 return SCM_UNSPECIFIED;
574 }
575 }
576 SCM_VELTS (o)[hval] =
577 scm_acons (s, SCM_UNDEFINED, SCM_VELTS (o)[hval]);
578 }
579 SCM_REALLOW_INTS;
580 return SCM_UNSPECIFIED;
581 }
582 #undef FUNC_NAME
583
584 SCM_DEFINE (scm_unintern_symbol, "unintern-symbol", 2, 0, 0,
585 (SCM o, SCM s),
586 "Remove the symbol with name @var{string} from @var{obarray}. This\n"
587 "function returns @code{#t} if the symbol was present and @code{#f}\n"
588 "otherwise.")
589 #define FUNC_NAME s_scm_unintern_symbol
590 {
591 scm_sizet hval;
592 SCM_VALIDATE_SYMBOL (2,s);
593 if (o == SCM_BOOL_F)
594 o = scm_symhash;
595 SCM_VALIDATE_VECTOR (1,o);
596 hval = scm_strhash (SCM_UCHARS (s), SCM_LENGTH (s), SCM_LENGTH(o));
597 SCM_DEFER_INTS;
598 {
599 SCM lsym_follow;
600 SCM lsym;
601 SCM sym;
602 for (lsym = SCM_VELTS (o)[hval], lsym_follow = SCM_BOOL_F;
603 SCM_NIMP (lsym);
604 lsym_follow = lsym, lsym = SCM_CDR (lsym))
605 {
606 sym = SCM_CAR (lsym);
607 if (SCM_CAR (sym) == s)
608 {
609 /* Found the symbol to unintern. */
610 if (lsym_follow == SCM_BOOL_F)
611 SCM_VELTS(o)[hval] = lsym;
612 else
613 SCM_SETCDR (lsym_follow, SCM_CDR(lsym));
614 SCM_ALLOW_INTS;
615 return SCM_BOOL_T;
616 }
617 }
618 }
619 SCM_ALLOW_INTS;
620 return SCM_BOOL_F;
621 }
622 #undef FUNC_NAME
623
624 SCM_DEFINE (scm_symbol_binding, "symbol-binding", 2, 0, 0,
625 (SCM o, SCM s),
626 "Look up in @var{obarray} the symbol whose name is @var{string}, and\n"
627 "return the value to which it is bound. If @var{obarray} is @code{#f},\n"
628 "use the global symbol table. If @var{string} is not interned in\n"
629 "@var{obarray}, an error is signalled.")
630 #define FUNC_NAME s_scm_symbol_binding
631 {
632 SCM vcell;
633 SCM_VALIDATE_SYMBOL (2,s);
634 if (o == SCM_BOOL_F)
635 o = scm_symhash;
636 SCM_VALIDATE_VECTOR (1,o);
637 vcell = scm_sym2ovcell (s, o);
638 return SCM_CDR(vcell);
639 }
640 #undef FUNC_NAME
641
642
643 SCM_DEFINE (scm_symbol_interned_p, "symbol-interned?", 2, 0, 0,
644 (SCM o, SCM s),
645 "Return @var{#t} if @var{obarray} contains a symbol with name\n"
646 "@var{string}, and @var{#f} otherwise.")
647 #define FUNC_NAME s_scm_symbol_interned_p
648 {
649 SCM vcell;
650 SCM_VALIDATE_SYMBOL (2,s);
651 if (o == SCM_BOOL_F)
652 o = scm_symhash;
653 SCM_VALIDATE_VECTOR (1,o);
654 vcell = scm_sym2ovcell_soft (s, o);
655 if (SCM_IMP(vcell) && (o == scm_symhash))
656 vcell = scm_sym2ovcell_soft (s, scm_weak_symhash);
657 return (SCM_NIMP(vcell)
658 ? SCM_BOOL_T
659 : SCM_BOOL_F);
660 }
661 #undef FUNC_NAME
662
663
664 SCM_DEFINE (scm_symbol_bound_p, "symbol-bound?", 2, 0, 0,
665 (SCM o, SCM s),
666 "Return @var{#t} if @var{obarray} contains a symbol with name\n"
667 "@var{string} bound to a defined value. This differs from\n"
668 "@var{symbol-bound?} in that the mere mention of a symbol usually causes\n"
669 "it to be interned; @code{symbol-bound?} determines whether a symbol has\n"
670 "been given any meaningful value.")
671 #define FUNC_NAME s_scm_symbol_bound_p
672 {
673 SCM vcell;
674 SCM_VALIDATE_SYMBOL (2,s);
675 if (o == SCM_BOOL_F)
676 o = scm_symhash;
677 SCM_VALIDATE_VECTOR (1,o);
678 vcell = scm_sym2ovcell_soft (s, o);
679 return (( SCM_NIMP(vcell)
680 && (SCM_CDR(vcell) != SCM_UNDEFINED))
681 ? SCM_BOOL_T
682 : SCM_BOOL_F);
683 }
684 #undef FUNC_NAME
685
686
687 SCM_DEFINE (scm_symbol_set_x, "symbol-set!", 3, 0, 0,
688 (SCM o, SCM s, SCM v),
689 "Find the symbol in @var{obarray} whose name is @var{string}, and rebind\n"
690 "it to @var{value}. An error is signalled if @var{string} is not present\n"
691 "in @var{obarray}.")
692 #define FUNC_NAME s_scm_symbol_set_x
693 {
694 SCM vcell;
695 SCM_VALIDATE_SYMBOL (2,s);
696 if (o == SCM_BOOL_F)
697 o = scm_symhash;
698 SCM_VALIDATE_VECTOR (1,o);
699 vcell = scm_sym2ovcell (s, o);
700 SCM_SETCDR (vcell, v);
701 return SCM_UNSPECIFIED;
702 }
703 #undef FUNC_NAME
704
705 static void
706 msymbolize (SCM s)
707 {
708 SCM string;
709 string = scm_makfromstr (SCM_CHARS (s), SCM_LENGTH (s), SCM_SYMBOL_SLOTS);
710 SCM_SETCHARS (s, SCM_CHARS (string));
711 SCM_SETLENGTH (s, SCM_LENGTH (s), scm_tc7_msymbol);
712 SCM_SETCDR (string, SCM_EOL);
713 SCM_SETCAR (string, SCM_EOL);
714 SCM_SYMBOL_PROPS (s) = SCM_EOL;
715 /* If it's a tc7_ssymbol, it comes from scm_symhash */
716 SCM_SYMBOL_HASH (s) = scm_strhash (SCM_UCHARS (s),
717 (scm_sizet) SCM_LENGTH (s),
718 SCM_LENGTH (scm_symhash));
719 }
720
721
722 SCM_DEFINE (scm_symbol_fref, "symbol-fref", 1, 0, 0,
723 (SCM s),
724 "Return the contents of @var{symbol}'s @dfn{function slot}.")
725 #define FUNC_NAME s_scm_symbol_fref
726 {
727 SCM_VALIDATE_SYMBOL (1,s);
728 SCM_DEFER_INTS;
729 if (SCM_TYP7(s) == scm_tc7_ssymbol)
730 msymbolize (s);
731 SCM_ALLOW_INTS;
732 return SCM_SYMBOL_FUNC (s);
733 }
734 #undef FUNC_NAME
735
736
737 SCM_DEFINE (scm_symbol_pref, "symbol-pref", 1, 0, 0,
738 (SCM s),
739 "Return the @dfn{property list} currently associated with @var{symbol}.")
740 #define FUNC_NAME s_scm_symbol_pref
741 {
742 SCM_VALIDATE_SYMBOL (1,s);
743 SCM_DEFER_INTS;
744 if (SCM_TYP7(s) == scm_tc7_ssymbol)
745 msymbolize (s);
746 SCM_ALLOW_INTS;
747 return SCM_SYMBOL_PROPS (s);
748 }
749 #undef FUNC_NAME
750
751
752 SCM_DEFINE (scm_symbol_fset_x, "symbol-fset!", 2, 0, 0,
753 (SCM s, SCM val),
754 "Change the binding of @var{symbol}'s function slot.")
755 #define FUNC_NAME s_scm_symbol_fset_x
756 {
757 SCM_VALIDATE_SYMBOL (1,s);
758 SCM_DEFER_INTS;
759 if (SCM_TYP7(s) == scm_tc7_ssymbol)
760 msymbolize (s);
761 SCM_ALLOW_INTS;
762 SCM_SYMBOL_FUNC (s) = val;
763 return SCM_UNSPECIFIED;
764 }
765 #undef FUNC_NAME
766
767
768 SCM_DEFINE (scm_symbol_pset_x, "symbol-pset!", 2, 0, 0,
769 (SCM s, SCM val),
770 "Change the binding of @var{symbol}'s property slot.")
771 #define FUNC_NAME s_scm_symbol_pset_x
772 {
773 SCM_VALIDATE_SYMBOL (1,s);
774 SCM_DEFER_INTS;
775 if (SCM_TYP7(s) == scm_tc7_ssymbol)
776 msymbolize (s);
777 SCM_SYMBOL_PROPS (s) = val;
778 SCM_ALLOW_INTS;
779 return SCM_UNSPECIFIED;
780 }
781 #undef FUNC_NAME
782
783
784 SCM_DEFINE (scm_symbol_hash, "symbol-hash", 1, 0, 0,
785 (SCM s),
786 "Return the hash value derived from @var{symbol}'s name, i.e. the integer\n"
787 "index into @var{symbol}'s obarray at which it is stored.")
788 #define FUNC_NAME s_scm_symbol_hash
789 {
790 SCM_VALIDATE_SYMBOL (1,s);
791 if (SCM_TYP7(s) == scm_tc7_ssymbol)
792 msymbolize (s);
793 return SCM_MAKINUM ((unsigned long)s ^ SCM_SYMBOL_HASH (s));
794 }
795 #undef FUNC_NAME
796
797
798 static void
799 copy_and_prune_obarray (SCM from, SCM to)
800 {
801 int i;
802 int length = SCM_LENGTH (from);
803 for (i = 0; i < length; ++i)
804 {
805 SCM head = SCM_VELTS (from)[i]; /* GC protection */
806 SCM ls = head;
807 SCM res = SCM_EOL;
808 SCM *lloc = &res;
809 while (SCM_NIMP (ls))
810 {
811 if (!SCM_UNBNDP (SCM_CDAR (ls)))
812 {
813 *lloc = scm_cons (SCM_CAR (ls), SCM_EOL);
814 lloc = SCM_CDRLOC (*lloc);
815 }
816 ls = SCM_CDR (ls);
817 }
818 SCM_VELTS (to)[i] = res;
819 }
820 }
821
822
823 SCM_DEFINE (scm_builtin_bindings, "builtin-bindings", 0, 0, 0,
824 (),
825 "Create and return a copy of the global symbol table, removing all\n"
826 "unbound symbols.")
827 #define FUNC_NAME s_scm_builtin_bindings
828 {
829 int length = SCM_LENGTH (scm_symhash);
830 SCM obarray = scm_make_vector (SCM_MAKINUM (length), SCM_EOL);
831 copy_and_prune_obarray (scm_symhash, obarray);
832 return obarray;
833 }
834 #undef FUNC_NAME
835
836
837 SCM_DEFINE (scm_builtin_weak_bindings, "builtin-weak-bindings", 0, 0, 0,
838 (),
839 "")
840 #define FUNC_NAME s_scm_builtin_weak_bindings
841 {
842 int length = SCM_LENGTH (scm_weak_symhash);
843 SCM obarray = scm_make_doubly_weak_hash_table (SCM_MAKINUM (length));
844 copy_and_prune_obarray (scm_weak_symhash, obarray);
845 return obarray;
846 }
847 #undef FUNC_NAME
848
849 static int gensym_counter;
850 static SCM gensym_prefix;
851
852 /* :FIXME:OPTIMIZE */
853 SCM_DEFINE (scm_gensym, "gensym", 0, 2, 0,
854 (SCM name, SCM obarray),
855 "Create a new, unique symbol in @var{obarray}, using the global symbol\n"
856 "table by default. If @var{name} is specified, it should be used as a\n"
857 "prefix for the new symbol's name. The default prefix is @code{%%gensym}.")
858 #define FUNC_NAME s_scm_gensym
859 {
860 SCM new;
861 if (SCM_UNBNDP (name))
862 name = gensym_prefix;
863 else
864 SCM_VALIDATE_ROSTRING (1,name);
865
866 new = name;
867 if (SCM_UNBNDP (obarray))
868 {
869 obarray = SCM_BOOL_F;
870 goto skip_test;
871 }
872 else
873 SCM_ASSERT ((SCM_VECTORP (obarray) || SCM_WVECTP (obarray)),
874 obarray,
875 SCM_ARG2,
876 FUNC_NAME);
877 while (scm_string_to_obarray_symbol (obarray, new, SCM_BOOL_T)
878 != SCM_BOOL_F)
879 skip_test:
880 new = scm_string_append
881 (scm_cons2 (name,
882 scm_number_to_string (SCM_MAKINUM (gensym_counter++),
883 SCM_UNDEFINED),
884 SCM_EOL));
885 return scm_string_to_obarray_symbol (obarray, new, SCM_BOOL_F);
886 }
887 #undef FUNC_NAME
888
889 void
890 scm_init_symbols ()
891 {
892 gensym_counter = 0;
893 gensym_prefix = scm_permanent_object (scm_makfrom0str ("%%gensym"));
894 #include "symbols.x"
895 }