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