* Tests that rely on garbage collection: Be aware of conservative scanning.
[bpt/guile.git] / libguile / symbols.c
CommitLineData
bccb33a9 1/* Copyright (C) 1995,1996,1997,1998, 2000 Free Software Foundation, Inc.
0f2d19dd
JB
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
82892bed
JB
15 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
16 * Boston, MA 02111-1307 USA
0f2d19dd
JB
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.
82892bed 40 * If you do not wish that, delete this exception notice. */
1bbd0b84
GB
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
0f2d19dd
JB
45\f
46
47#include <stdio.h>
a0599745
MD
48#include "libguile/_scm.h"
49#include "libguile/chars.h"
50#include "libguile/eval.h"
fb43bf74 51#include "libguile/smob.h"
a0599745
MD
52#include "libguile/variable.h"
53#include "libguile/alist.h"
7e73eaee 54#include "libguile/fluids.h"
a0599745
MD
55#include "libguile/strings.h"
56#include "libguile/vectors.h"
57#include "libguile/weaks.h"
eb8db440 58#include "libguile/modules.h"
a0599745
MD
59
60#include "libguile/validate.h"
61#include "libguile/symbols.h"
0f2d19dd 62
95b88819
GH
63#ifdef HAVE_STRING_H
64#include <string.h>
65#endif
66
0f2d19dd
JB
67\f
68
0f2d19dd
JB
69/* NUM_HASH_BUCKETS is the number of symbol scm_hash table buckets.
70 */
71#define NUM_HASH_BUCKETS 137
72
73\f
74
28b06554
DH
75static char *
76duplicate_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
0f2d19dd
JB
84
85/* {Symbols}
86 */
87
1cc91f1b 88
0f2d19dd 89unsigned long
28b06554 90scm_string_hash (const unsigned char *str, scm_sizet len)
0f2d19dd
JB
91{
92 if (len > 5)
93 {
94 scm_sizet i = 5;
28b06554 95 unsigned long h = 264;
0f2d19dd 96 while (i--)
28b06554 97 h = (h << 8) + ((unsigned) (scm_downcase (str[h % len])));
0f2d19dd
JB
98 return h;
99 }
100 else
101 {
102 scm_sizet i = len;
103 unsigned long h = 0;
104 while (i)
28b06554 105 h = (h << 8) + ((unsigned) (scm_downcase (str[--i])));
0f2d19dd
JB
106 return h;
107 }
108}
109
28b06554 110
0f2d19dd
JB
111int scm_symhash_dim = NUM_HASH_BUCKETS;
112
113
114/* scm_sym2vcell
115 * looks up the symbol in the symhash table.
116 */
1cc91f1b 117
0f2d19dd 118SCM
bccb33a9 119scm_sym2vcell (SCM sym, SCM thunk, SCM definep)
0f2d19dd 120{
bccb33a9 121 if (SCM_NIMP (thunk))
0f2d19dd 122 {
bccb33a9
MD
123 SCM var;
124
fb43bf74 125 if (SCM_EVAL_CLOSURE_P (thunk))
bccb33a9 126 /* Bypass evaluator in the standard case. */
fb43bf74 127 var = scm_eval_closure_lookup (thunk, sym, definep);
bccb33a9
MD
128 else
129 var = scm_apply (thunk, sym, scm_cons (definep, scm_listofnull));
0f2d19dd 130
bc66755e 131 if (SCM_FALSEP (var))
0f2d19dd
JB
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;
28b06554
DH
145 scm_sizet hash
146 = scm_string_hash (SCM_UCHARS (sym), SCM_LENGTH (sym)) % scm_symhash_dim;
0f2d19dd
JB
147
148 SCM_DEFER_INTS;
28b06554 149 for (lsym = SCM_VELTS (scm_symhash)[hash]; SCM_NIMP (lsym); lsym = SCM_CDR (lsym))
0f2d19dd
JB
150 {
151 z = SCM_CAR (lsym);
bc66755e 152 if (SCM_EQ_P (SCM_CAR (z), sym))
0f2d19dd
JB
153 {
154 SCM_ALLOW_INTS;
155 return z;
156 }
157 }
158
28b06554 159 for (lsym = *(lsymp = &SCM_VELTS (scm_weak_symhash)[hash]);
0f2d19dd 160 SCM_NIMP (lsym);
25d8012c 161 lsym = *(lsymp = SCM_CDRLOC (lsym)))
0f2d19dd
JB
162 {
163 z = SCM_CAR (lsym);
bc66755e 164 if (SCM_EQ_P (SCM_CAR (z), sym))
0f2d19dd 165 {
5aab5d96 166 if (SCM_NFALSEP (definep))
0f2d19dd 167 {
49bc24fe 168 /* Move handle from scm_weak_symhash to scm_symhash. */
0f2d19dd 169 *lsymp = SCM_CDR (lsym);
28b06554
DH
170 SCM_SETCDR (lsym, SCM_VELTS(scm_symhash)[hash]);
171 SCM_VELTS(scm_symhash)[hash] = lsym;
0f2d19dd
JB
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
49bc24fe 183 * looks up the symbol in an arbitrary obarray.
0f2d19dd 184 */
1cc91f1b 185
0f2d19dd 186SCM
1bbd0b84 187scm_sym2ovcell_soft (SCM sym, SCM obarray)
0f2d19dd
JB
188{
189 SCM lsym, z;
28b06554
DH
190 scm_sizet hash
191 = scm_string_hash (SCM_UCHARS (sym), SCM_LENGTH (sym)) % SCM_LENGTH (obarray);
0f2d19dd 192 SCM_REDEFER_INTS;
28b06554 193 for (lsym = SCM_VELTS (obarray)[hash];
0f2d19dd
JB
194 SCM_NIMP (lsym);
195 lsym = SCM_CDR (lsym))
196 {
197 z = SCM_CAR (lsym);
bc66755e 198 if (SCM_EQ_P (SCM_CAR (z), sym))
0f2d19dd
JB
199 {
200 SCM_REALLOW_INTS;
201 return z;
202 }
203 }
204 SCM_REALLOW_INTS;
205 return SCM_BOOL_F;
206}
207
1cc91f1b 208
0f2d19dd 209SCM
1bbd0b84 210scm_sym2ovcell (SCM sym, SCM obarray)
0f2d19dd
JB
211{
212 SCM answer;
213 answer = scm_sym2ovcell_soft (sym, obarray);
bc66755e 214 if (!SCM_FALSEP (answer))
0f2d19dd
JB
215 return answer;
216 scm_wta (sym, "uninterned symbol? ", "");
217 return SCM_UNSPECIFIED; /* not reached */
218}
219
8ce94504
JB
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
1cc91f1b 242
0f2d19dd 243SCM
28b06554 244scm_intern_obarray_soft (const char *name,scm_sizet len,SCM obarray,unsigned int softness)
0f2d19dd 245{
28b06554
DH
246 scm_sizet raw_hash = scm_string_hash ((unsigned char *) name, len);
247 scm_sizet hash;
0f2d19dd 248 SCM lsym;
0f2d19dd
JB
249
250 SCM_REDEFER_INTS;
251
bc66755e 252 if (SCM_FALSEP (obarray))
0f2d19dd 253 {
28b06554 254 hash = raw_hash % 1019;
0f2d19dd
JB
255 goto uninterned_symbol;
256 }
257
28b06554 258 hash = raw_hash % SCM_LENGTH (obarray);
0f2d19dd
JB
259
260 retry_new_obarray:
28b06554 261 for (lsym = SCM_VELTS (obarray)[hash]; SCM_NIMP (lsym); lsym = SCM_CDR (lsym))
0f2d19dd 262 {
28b06554
DH
263 scm_sizet i;
264 SCM a = SCM_CAR (lsym);
265 SCM z = SCM_CAR (a);
266 unsigned char *tmp = SCM_UCHARS (z);
0f2d19dd
JB
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 {
0f2d19dd
JB
273 SCM_REALLOW_INTS;
274 return a;
275 }
276 trynext:;
277 }
278
bc66755e 279 if (SCM_EQ_P (obarray, scm_symhash))
0f2d19dd
JB
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
28b06554
DH
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);
0f2d19dd 297
cf551a2b 298 SCM_SET_SYMBOL_PROPS (lsym, SCM_EOL);
bc66755e 299 if (SCM_FALSEP (obarray))
0f2d19dd
JB
300 {
301 SCM answer;
302 SCM_REALLOW_INTS;
303 SCM_NEWCELL (answer);
304 SCM_DEFER_INTS;
25d8012c
MD
305 SCM_SETCAR (answer, lsym);
306 SCM_SETCDR (answer, SCM_UNDEFINED);
0f2d19dd
JB
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);
28b06554
DH
320 SCM_SETCDR (b, SCM_VELTS(obarray)[hash]);
321 SCM_VELTS(obarray)[hash] = b;
0f2d19dd
JB
322 SCM_REALLOW_INTS;
323 return SCM_CAR (b);
324 }
325}
326
1cc91f1b 327
0f2d19dd 328SCM
1bbd0b84 329scm_intern_obarray (const char *name,scm_sizet len,SCM obarray)
0f2d19dd
JB
330{
331 return scm_intern_obarray_soft (name, len, obarray, 0);
332}
333
334
0f2d19dd 335SCM
1bbd0b84 336scm_intern (const char *name,scm_sizet len)
0f2d19dd
JB
337{
338 return scm_intern_obarray (name, len, scm_symhash);
339}
340
1cc91f1b 341
0f2d19dd 342SCM
1bbd0b84 343scm_intern0 (const char * name)
0f2d19dd
JB
344{
345 return scm_intern (name, strlen (name));
346}
347
348
5aab5d96 349/* Intern the symbol named NAME in scm_symhash, NAME is null-terminated. */
0f2d19dd 350SCM
1bbd0b84 351scm_sysintern0_no_module_lookup (const char *name)
0f2d19dd
JB
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 {
0f2d19dd
JB
358 SCM_ALLOW_INTS;
359 return easy_answer;
360 }
361 else
362 {
363 SCM lsym;
364 scm_sizet len = strlen (name);
28b06554
DH
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);
0f2d19dd 369 SCM_SETCHARS (lsym, name);
28b06554
DH
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
5aab5d96 374 lsym = scm_cons (lsym, SCM_UNDEFINED);
28b06554 375 SCM_VELTS (scm_symhash)[hash] = scm_cons (lsym, SCM_VELTS (scm_symhash)[hash]);
0f2d19dd
JB
376 SCM_ALLOW_INTS;
377 return lsym;
378 }
379}
380
9b8d3288
MV
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 */
385SCM
1bbd0b84 386scm_sysintern (const char *name, SCM val)
5aab5d96
MD
387{
388 SCM vcell = scm_sysintern0 (name);
389 SCM_SETCDR (vcell, val);
390 return vcell;
391}
392
393SCM
1bbd0b84 394scm_sysintern0 (const char *name)
9b8d3288
MV
395{
396 SCM lookup_proc;
eb8db440
MD
397 if (scm_module_system_booted_p
398 && SCM_NIMP (lookup_proc = SCM_TOP_LEVEL_LOOKUP_CLOSURE))
9b8d3288
MV
399 {
400 SCM sym = SCM_CAR (scm_intern0 (name));
401 SCM vcell = scm_sym2vcell (sym, lookup_proc, SCM_BOOL_T);
bc66755e 402 if (SCM_FALSEP (vcell))
5d2d2ffc 403 scm_misc_error ("sysintern0", "can't define variable", sym);
9b8d3288
MV
404 return vcell;
405 }
406 else
5aab5d96 407 return scm_sysintern0_no_module_lookup (name);
9b8d3288
MV
408}
409
1dd28b3d
MD
410/* Lookup the value of the symbol named by the nul-terminated string
411 NAME in the current module. */
412SCM
1bbd0b84 413scm_symbol_value0 (const char *name)
1dd28b3d
MD
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),
7e73eaee 420 SCM_TOP_LEVEL_LOOKUP_CLOSURE,
1dd28b3d
MD
421 SCM_BOOL_F);
422 if (SCM_FALSEP (vcell))
423 return SCM_UNDEFINED;
424 return SCM_CDR (vcell);
425}
426
3b3b36dd 427SCM_DEFINE (scm_symbol_p, "symbol?", 1, 0, 0,
5ffe9968
GB
428 (SCM obj),
429 "Returns @t{#t} if @var{obj} is a symbol, otherwise returns @t{#f}. (r5rs)")
1bbd0b84 430#define FUNC_NAME s_scm_symbol_p
0f2d19dd 431{
5ffe9968
GB
432 if SCM_IMP(obj) return SCM_BOOL_F;
433 return SCM_BOOL(SCM_SYMBOLP(obj));
0f2d19dd 434}
1bbd0b84 435#undef FUNC_NAME
0f2d19dd 436
3b3b36dd 437SCM_DEFINE (scm_symbol_to_string, "symbol->string", 1, 0, 0,
1bbd0b84 438 (SCM s),
5ffe9968 439 "Returns the name of @var{symbol} as a string. If the symbol was part of\n"
ae42688c
NJ
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"
5ffe9968
GB
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"
ae42688c
NJ
457 " (string->symbol \"Malvina\")) \n"
458 " ==> \"Malvina\"\n"
5ffe9968
GB
459 "}\n"
460 "@end format")
1bbd0b84 461#define FUNC_NAME s_scm_symbol_to_string
0f2d19dd 462{
28b06554
DH
463 SCM_VALIDATE_SYMBOL (1, s);
464 return scm_makfromstr (SCM_CHARS (s), SCM_LENGTH (s), 0);
0f2d19dd 465}
1bbd0b84 466#undef FUNC_NAME
0f2d19dd
JB
467
468
3b3b36dd 469SCM_DEFINE (scm_string_to_symbol, "string->symbol", 1, 0, 0,
1bbd0b84 470 (SCM s),
5ffe9968
GB
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")
1bbd0b84 496#define FUNC_NAME s_scm_string_to_symbol
0f2d19dd
JB
497{
498 SCM vcell;
499 SCM answer;
500
3b3b36dd 501 SCM_VALIDATE_ROSTRING (1,s);
0f2d19dd
JB
502 vcell = scm_intern(SCM_ROCHARS(s), (scm_sizet)SCM_LENGTH(s));
503 answer = SCM_CAR (vcell);
0f2d19dd
JB
504 return answer;
505}
1bbd0b84 506#undef FUNC_NAME
0f2d19dd
JB
507
508
3b3b36dd 509SCM_DEFINE (scm_string_to_obarray_symbol, "string->obarray-symbol", 2, 1, 0,
1bbd0b84 510 (SCM o, SCM s, SCM softp),
a3c8b9fc
MD
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}.")
1bbd0b84 522#define FUNC_NAME s_scm_string_to_obarray_symbol
0f2d19dd
JB
523{
524 SCM vcell;
525 SCM answer;
526 int softness;
527
3b3b36dd 528 SCM_VALIDATE_ROSTRING (2,s);
bc66755e 529 SCM_ASSERT (SCM_BOOLP (o) || SCM_VECTORP (o), o, SCM_ARG1, FUNC_NAME);
0f2d19dd 530
bc66755e 531 softness = (!SCM_UNBNDP (softp) && !SCM_FALSEP(softp));
0f2d19dd 532 /* iron out some screwy calling conventions */
bc66755e 533 if (SCM_FALSEP (o))
0f2d19dd 534 o = scm_symhash;
9a09deb1 535 else if (SCM_EQ_P (o, SCM_BOOL_T))
0f2d19dd
JB
536 o = SCM_BOOL_F;
537
49bc24fe
MD
538 vcell = scm_intern_obarray_soft (SCM_ROCHARS(s),
539 (scm_sizet)SCM_ROLENGTH(s),
540 o,
541 softness);
bc66755e 542 if (SCM_FALSEP (vcell))
0f2d19dd
JB
543 return vcell;
544 answer = SCM_CAR (vcell);
0f2d19dd
JB
545 return answer;
546}
1bbd0b84 547#undef FUNC_NAME
0f2d19dd 548
3b3b36dd 549SCM_DEFINE (scm_intern_symbol, "intern-symbol", 2, 0, 0,
1bbd0b84 550 (SCM o, SCM s),
b380b885
MD
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.")
1bbd0b84 554#define FUNC_NAME s_scm_intern_symbol
0f2d19dd 555{
49bc24fe 556 scm_sizet hval;
3b3b36dd 557 SCM_VALIDATE_SYMBOL (2,s);
bc66755e 558 if (SCM_FALSEP (o))
49bc24fe 559 o = scm_symhash;
3b3b36dd 560 SCM_VALIDATE_VECTOR (1,o);
28b06554 561 hval = scm_string_hash (SCM_UCHARS (s), SCM_LENGTH (s)) % SCM_LENGTH (o);
49bc24fe
MD
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);
bc66755e 572 if (SCM_EQ_P (SCM_CAR (sym), s))
49bc24fe
MD
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;
0f2d19dd 583}
1bbd0b84 584#undef FUNC_NAME
0f2d19dd 585
3b3b36dd 586SCM_DEFINE (scm_unintern_symbol, "unintern-symbol", 2, 0, 0,
1bbd0b84 587 (SCM o, SCM s),
b380b885
MD
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.")
1bbd0b84 591#define FUNC_NAME s_scm_unintern_symbol
0f2d19dd 592{
49bc24fe 593 scm_sizet hval;
3b3b36dd 594 SCM_VALIDATE_SYMBOL (2,s);
bc66755e 595 if (SCM_FALSEP (o))
49bc24fe 596 o = scm_symhash;
3b3b36dd 597 SCM_VALIDATE_VECTOR (1,o);
28b06554 598 hval = scm_string_hash (SCM_UCHARS (s), SCM_LENGTH (s)) % SCM_LENGTH (o);
49bc24fe
MD
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);
bc66755e 609 if (SCM_EQ_P (SCM_CAR (sym), s))
49bc24fe
MD
610 {
611 /* Found the symbol to unintern. */
bc66755e 612 if (SCM_FALSEP (lsym_follow))
49bc24fe
MD
613 SCM_VELTS(o)[hval] = lsym;
614 else
25d8012c 615 SCM_SETCDR (lsym_follow, SCM_CDR(lsym));
49bc24fe
MD
616 SCM_ALLOW_INTS;
617 return SCM_BOOL_T;
618 }
619 }
620 }
621 SCM_ALLOW_INTS;
622 return SCM_BOOL_F;
0f2d19dd 623}
1bbd0b84 624#undef FUNC_NAME
0f2d19dd 625
3b3b36dd 626SCM_DEFINE (scm_symbol_binding, "symbol-binding", 2, 0, 0,
1bbd0b84 627 (SCM o, SCM s),
b380b885
MD
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.")
1bbd0b84 632#define FUNC_NAME s_scm_symbol_binding
0f2d19dd
JB
633{
634 SCM vcell;
3b3b36dd 635 SCM_VALIDATE_SYMBOL (2,s);
bc66755e 636 if (SCM_FALSEP (o))
0f2d19dd 637 o = scm_symhash;
3b3b36dd 638 SCM_VALIDATE_VECTOR (1,o);
0f2d19dd
JB
639 vcell = scm_sym2ovcell (s, o);
640 return SCM_CDR(vcell);
641}
1bbd0b84 642#undef FUNC_NAME
0f2d19dd
JB
643
644
3b3b36dd 645SCM_DEFINE (scm_symbol_interned_p, "symbol-interned?", 2, 0, 0,
1bbd0b84 646 (SCM o, SCM s),
b380b885
MD
647 "Return @var{#t} if @var{obarray} contains a symbol with name\n"
648 "@var{string}, and @var{#f} otherwise.")
1bbd0b84 649#define FUNC_NAME s_scm_symbol_interned_p
0f2d19dd
JB
650{
651 SCM vcell;
3b3b36dd 652 SCM_VALIDATE_SYMBOL (2,s);
bc66755e 653 if (SCM_FALSEP (o))
0f2d19dd 654 o = scm_symhash;
3b3b36dd 655 SCM_VALIDATE_VECTOR (1,o);
0f2d19dd 656 vcell = scm_sym2ovcell_soft (s, o);
bc66755e 657 if (SCM_IMP (vcell) && SCM_EQ_P (o, scm_symhash))
0f2d19dd
JB
658 vcell = scm_sym2ovcell_soft (s, scm_weak_symhash);
659 return (SCM_NIMP(vcell)
660 ? SCM_BOOL_T
661 : SCM_BOOL_F);
662}
1bbd0b84 663#undef FUNC_NAME
0f2d19dd
JB
664
665
3b3b36dd 666SCM_DEFINE (scm_symbol_bound_p, "symbol-bound?", 2, 0, 0,
1bbd0b84 667 (SCM o, SCM s),
b380b885
MD
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.")
1bbd0b84 673#define FUNC_NAME s_scm_symbol_bound_p
0f2d19dd
JB
674{
675 SCM vcell;
3b3b36dd 676 SCM_VALIDATE_SYMBOL (2,s);
bc66755e 677 if (SCM_FALSEP (o))
0f2d19dd 678 o = scm_symhash;
3b3b36dd 679 SCM_VALIDATE_VECTOR (1,o);
0f2d19dd 680 vcell = scm_sym2ovcell_soft (s, o);
bc66755e 681 return SCM_BOOL (SCM_NIMP (vcell) && !SCM_UNBNDP (SCM_CDR (vcell)));
0f2d19dd 682}
1bbd0b84 683#undef FUNC_NAME
0f2d19dd
JB
684
685
3b3b36dd 686SCM_DEFINE (scm_symbol_set_x, "symbol-set!", 3, 0, 0,
1bbd0b84 687 (SCM o, SCM s, SCM v),
b380b885
MD
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}.")
1bbd0b84 691#define FUNC_NAME s_scm_symbol_set_x
0f2d19dd
JB
692{
693 SCM vcell;
3b3b36dd 694 SCM_VALIDATE_SYMBOL (2,s);
bc66755e 695 if (SCM_FALSEP (o))
0f2d19dd 696 o = scm_symhash;
3b3b36dd 697 SCM_VALIDATE_VECTOR (1,o);
0f2d19dd 698 vcell = scm_sym2ovcell (s, o);
25d8012c 699 SCM_SETCDR (vcell, v);
0f2d19dd
JB
700 return SCM_UNSPECIFIED;
701}
1bbd0b84 702#undef FUNC_NAME
0f2d19dd 703
0f2d19dd 704
3b3b36dd 705SCM_DEFINE (scm_symbol_fref, "symbol-fref", 1, 0, 0,
1bbd0b84 706 (SCM s),
b380b885 707 "Return the contents of @var{symbol}'s @dfn{function slot}.")
1bbd0b84 708#define FUNC_NAME s_scm_symbol_fref
0f2d19dd 709{
3b3b36dd 710 SCM_VALIDATE_SYMBOL (1,s);
0f2d19dd
JB
711 return SCM_SYMBOL_FUNC (s);
712}
1bbd0b84 713#undef FUNC_NAME
0f2d19dd
JB
714
715
3b3b36dd 716SCM_DEFINE (scm_symbol_pref, "symbol-pref", 1, 0, 0,
1bbd0b84 717 (SCM s),
b380b885 718 "Return the @dfn{property list} currently associated with @var{symbol}.")
1bbd0b84 719#define FUNC_NAME s_scm_symbol_pref
0f2d19dd 720{
3b3b36dd 721 SCM_VALIDATE_SYMBOL (1,s);
0f2d19dd
JB
722 return SCM_SYMBOL_PROPS (s);
723}
1bbd0b84 724#undef FUNC_NAME
0f2d19dd
JB
725
726
3b3b36dd 727SCM_DEFINE (scm_symbol_fset_x, "symbol-fset!", 2, 0, 0,
1bbd0b84 728 (SCM s, SCM val),
b380b885 729 "Change the binding of @var{symbol}'s function slot.")
1bbd0b84 730#define FUNC_NAME s_scm_symbol_fset_x
0f2d19dd 731{
3b3b36dd 732 SCM_VALIDATE_SYMBOL (1,s);
cf551a2b 733 SCM_SET_SYMBOL_FUNC (s, val);
0f2d19dd
JB
734 return SCM_UNSPECIFIED;
735}
1bbd0b84 736#undef FUNC_NAME
0f2d19dd
JB
737
738
3b3b36dd 739SCM_DEFINE (scm_symbol_pset_x, "symbol-pset!", 2, 0, 0,
1bbd0b84 740 (SCM s, SCM val),
b380b885 741 "Change the binding of @var{symbol}'s property slot.")
1bbd0b84 742#define FUNC_NAME s_scm_symbol_pset_x
0f2d19dd 743{
3b3b36dd 744 SCM_VALIDATE_SYMBOL (1,s);
0f2d19dd 745 SCM_DEFER_INTS;
cf551a2b 746 SCM_SET_SYMBOL_PROPS (s, val);
0f2d19dd
JB
747 SCM_ALLOW_INTS;
748 return SCM_UNSPECIFIED;
749}
1bbd0b84 750#undef FUNC_NAME
0f2d19dd
JB
751
752
3b3b36dd 753SCM_DEFINE (scm_symbol_hash, "symbol-hash", 1, 0, 0,
28b06554
DH
754 (SCM symbol),
755 "Return a hash value for @var{symbol}.")
1bbd0b84 756#define FUNC_NAME s_scm_symbol_hash
0f2d19dd 757{
28b06554
DH
758 SCM_VALIDATE_SYMBOL (1, symbol);
759 return SCM_MAKINUM (SCM_SYMBOL_HASH (symbol));
0f2d19dd 760}
1bbd0b84 761#undef FUNC_NAME
0f2d19dd
JB
762
763
b2530d66 764static void
1bbd0b84 765copy_and_prune_obarray (SCM from, SCM to)
b2530d66
MD
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
3b3b36dd 789SCM_DEFINE (scm_builtin_bindings, "builtin-bindings", 0, 0, 0,
5ffe9968 790 (),
b380b885
MD
791 "Create and return a copy of the global symbol table, removing all\n"
792 "unbound symbols.")
1bbd0b84 793#define FUNC_NAME s_scm_builtin_bindings
b2530d66
MD
794{
795 int length = SCM_LENGTH (scm_symhash);
a8741caa 796 SCM obarray = scm_make_vector (SCM_MAKINUM (length), SCM_EOL);
b2530d66
MD
797 copy_and_prune_obarray (scm_symhash, obarray);
798 return obarray;
799}
1bbd0b84 800#undef FUNC_NAME
b2530d66
MD
801
802
3b3b36dd 803SCM_DEFINE (scm_builtin_weak_bindings, "builtin-weak-bindings", 0, 0, 0,
5ffe9968 804 (),
b380b885 805 "")
1bbd0b84 806#define FUNC_NAME s_scm_builtin_weak_bindings
b2530d66
MD
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}
1bbd0b84 813#undef FUNC_NAME
b2530d66 814
e1313058
MD
815#define MAX_PREFIX_LENGTH 30
816
1ff4df7a 817static int gensym_counter;
e1313058
MD
818
819SCM_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.")
1bbd0b84 825#define FUNC_NAME s_scm_gensym
1ff4df7a 826{
e1313058
MD
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 }
1ff4df7a 835 else
c64d02c5 836 {
e1313058
MD
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);
c64d02c5 842 }
e1313058
MD
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
1bbd0b84 852
e1313058
MD
853static int gentemp_counter;
854
855SCM_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
1ff4df7a 874 {
e1313058
MD
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);
1ff4df7a 880 }
e1313058
MD
881
882 if (SCM_UNBNDP (obarray))
883 obarray = scm_symhash;
1ff4df7a 884 else
368cf54d 885 SCM_ASSERT ((SCM_VECTORP (obarray) || SCM_WVECTP (obarray)),
1ff4df7a
MD
886 obarray,
887 SCM_ARG2,
1bbd0b84 888 FUNC_NAME);
e1313058
MD
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 }
1ff4df7a 904}
1bbd0b84 905#undef FUNC_NAME
1cc91f1b 906
0f2d19dd
JB
907void
908scm_init_symbols ()
0f2d19dd 909{
1ff4df7a 910 gensym_counter = 0;
e1313058 911 gentemp_counter = 0;
a0599745 912#include "libguile/symbols.x"
0f2d19dd 913}
89e00824
ML
914
915/*
916 Local Variables:
917 c-file-style: "gnu"
918 End:
919*/