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