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