1 /* Copyright (C) 1995,1996,1997 Free Software Foundation, Inc.
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)
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.
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
18 * As a special exception, the Free Software Foundation gives permission
19 * for additional uses of the text contained in its release of GUILE.
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.
27 * This exception does not however invalidate any other reasons why
28 * the executable file might be covered by the GNU General Public License.
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.
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. */
60 /* NUM_HASH_BUCKETS is the number of symbol scm_hash table buckets.
62 #define NUM_HASH_BUCKETS 137
72 scm_strhash (str
, len
, n
)
80 unsigned long h
= 264 % n
;
82 h
= ((h
<< 8) + ((unsigned) (scm_downcase (str
[h
% len
])))) % n
;
90 h
= ((h
<< 8) + ((unsigned) (scm_downcase (str
[--i
])))) % n
;
95 int scm_symhash_dim
= NUM_HASH_BUCKETS
;
99 * looks up the symbol in the symhash table.
103 scm_sym2vcell (sym
, thunk
, definep
)
110 SCM var
= scm_apply (thunk
, sym
, scm_cons(definep
, scm_listofnull
));
112 if (var
== SCM_BOOL_F
)
116 if (SCM_IMP(var
) || !SCM_VARIABLEP (var
))
117 scm_wta (sym
, "strangely interned symbol? ", "");
118 return SCM_VARVCELL (var
);
126 scm_sizet scm_hash
= scm_strhash (SCM_UCHARS (sym
), (scm_sizet
) SCM_LENGTH (sym
),
127 (unsigned long) scm_symhash_dim
);
130 for (lsym
= SCM_VELTS (scm_symhash
)[scm_hash
]; SCM_NIMP (lsym
); lsym
= SCM_CDR (lsym
))
133 if (SCM_CAR (z
) == sym
)
140 for (lsym
= *(lsymp
= &SCM_VELTS (scm_weak_symhash
)[scm_hash
]);
142 lsym
= *(lsymp
= SCM_CDRLOC (lsym
)))
145 if (SCM_CAR (z
) == sym
)
147 if (SCM_NFALSEP (definep
))
149 /* Move handle from scm_weak_symhash to scm_symhash. */
150 *lsymp
= SCM_CDR (lsym
);
151 SCM_SETCDR (lsym
, SCM_VELTS(scm_symhash
)[scm_hash
]);
152 SCM_VELTS(scm_symhash
)[scm_hash
] = lsym
;
159 return scm_wta (sym
, "uninterned symbol? ", "");
164 * looks up the symbol in an arbitrary obarray.
168 scm_sym2ovcell_soft (sym
, obarray
)
175 scm_hash
= scm_strhash (SCM_UCHARS (sym
),
176 (scm_sizet
) SCM_LENGTH (sym
),
177 SCM_LENGTH (obarray
));
179 for (lsym
= SCM_VELTS (obarray
)[scm_hash
];
181 lsym
= SCM_CDR (lsym
))
184 if (SCM_CAR (z
) == sym
)
196 scm_sym2ovcell (sym
, obarray
)
201 answer
= scm_sym2ovcell_soft (sym
, obarray
);
202 if (answer
!= SCM_BOOL_F
)
204 scm_wta (sym
, "uninterned symbol? ", "");
205 return SCM_UNSPECIFIED
; /* not reached */
208 /* Intern a symbol whose name is the LEN characters at NAME in OBARRAY.
210 OBARRAY should be a vector of lists, indexed by the name's hash
211 value, modulo OBARRAY's length. Each list has the form
212 ((SYMBOL . VALUE) ...), where SYMBOL is a symbol, and VALUE is the
213 value associated with that symbol (in the current module? in the
216 To "intern" a symbol means: if OBARRAY already contains a symbol by
217 that name, return its (SYMBOL . VALUE) pair; otherwise, create a
218 new symbol, add the pair (SYMBOL . SCM_UNDEFINED) to the
219 appropriate list of the OBARRAY, and return the pair.
221 If softness is non-zero, don't create a symbol if it isn't already
222 in OBARRAY; instead, just return #f.
224 If OBARRAY is SCM_BOOL_F, create a symbol listed in no obarray and
225 return (SYMBOL . SCM_UNDEFINED).
227 If OBARRAY is scm_symhash, and that doesn't contain the symbol,
228 check scm_weak_symhash instead. */
232 scm_intern_obarray_soft (name
, len
, obarray
, softness
)
240 register scm_sizet i
;
241 register unsigned char *tmp
;
247 tmp
= (unsigned char *) name
;
249 if (obarray
== SCM_BOOL_F
)
251 scm_hash
= scm_strhash (tmp
, i
, 1019);
252 goto uninterned_symbol
;
255 scm_hash
= scm_strhash (tmp
, i
, SCM_LENGTH(obarray
));
257 /* softness == -1 used to mean that it was known that the symbol
258 wasn't already in the obarray. I don't think there are any
259 callers that use that case any more, but just in case...
265 for (lsym
= SCM_VELTS (obarray
)[scm_hash
]; SCM_NIMP (lsym
); lsym
= SCM_CDR (lsym
))
269 tmp
= SCM_UCHARS (z
);
270 if (SCM_LENGTH (z
) != len
)
273 if (((unsigned char *) name
)[i
] != tmp
[i
])
284 if (obarray
== scm_symhash
)
286 obarray
= scm_weak_symhash
;
287 goto retry_new_obarray
;
297 lsym
= scm_makfromstr (name
, len
, SCM_SYMBOL_SLOTS
);
299 SCM_SETLENGTH (lsym
, (long) len
, scm_tc7_msymbol
);
300 SCM_SYMBOL_HASH (lsym
) = scm_hash
;
301 SCM_SYMBOL_PROPS (lsym
) = SCM_EOL
;
302 if (obarray
== SCM_BOOL_F
)
306 SCM_NEWCELL (answer
);
308 SCM_SETCAR (answer
, lsym
);
309 SCM_SETCDR (answer
, SCM_UNDEFINED
);
320 SCM_SETCAR (a
, lsym
);
321 SCM_SETCDR (a
, SCM_UNDEFINED
);
323 SCM_SETCDR (b
, SCM_VELTS(obarray
)[scm_hash
]);
324 SCM_VELTS(obarray
)[scm_hash
] = b
;
332 scm_intern_obarray (name
, len
, obarray
)
337 return scm_intern_obarray_soft (name
, len
, obarray
, 0);
342 scm_intern (name
, len
)
346 return scm_intern_obarray (name
, len
, scm_symhash
);
354 return scm_intern (name
, strlen (name
));
358 /* Intern the symbol named NAME in scm_symhash, NAME is null-terminated. */
360 scm_sysintern0_no_module_lookup (name
)
365 easy_answer
= scm_intern_obarray_soft (name
, strlen (name
), scm_symhash
, 1);
366 if (SCM_NIMP (easy_answer
))
374 scm_sizet len
= strlen (name
);
375 register unsigned char *tmp
= (unsigned char *) name
;
376 scm_sizet scm_hash
= scm_strhash (tmp
, len
, (unsigned long) scm_symhash_dim
);
378 SCM_SETLENGTH (lsym
, (long) len
, scm_tc7_ssymbol
);
379 SCM_SETCHARS (lsym
, name
);
380 lsym
= scm_cons (lsym
, SCM_UNDEFINED
);
381 SCM_VELTS (scm_symhash
)[scm_hash
] = scm_cons (lsym
, SCM_VELTS (scm_symhash
)[scm_hash
]);
388 /* Is it safe to access SCM_TOP_LEVEL_LOOKUP_CLOSURE_VAR?
390 int scm_can_use_top_level_lookup_closure_var
;
392 /* Intern the symbol named NAME in scm_symhash, and give it the value
393 VAL. NAME is null-terminated. Use the current top_level lookup
394 closure to give NAME its value.
397 scm_sysintern (name
, val
)
401 SCM vcell
= scm_sysintern0 (name
);
402 SCM_SETCDR (vcell
, val
);
407 scm_sysintern0 (name
)
411 if (scm_can_use_top_level_lookup_closure_var
&&
412 SCM_NIMP (lookup_proc
= SCM_CDR (scm_top_level_lookup_closure_var
)))
414 SCM sym
= SCM_CAR (scm_intern0 (name
));
415 SCM vcell
= scm_sym2vcell (sym
, lookup_proc
, SCM_BOOL_T
);
416 if (vcell
== SCM_BOOL_F
)
417 scm_misc_error ("sysintern", "can't define variable", sym
);
421 return scm_sysintern0_no_module_lookup (name
);
424 /* Lookup the value of the symbol named by the nul-terminated string
425 NAME in the current module. */
427 scm_symbol_value0 (name
)
430 /* This looks silly - we look up the symbol twice. But it is in
431 fact necessary given the current module system because the module
432 lookup closures are written in scheme which needs real symbols. */
433 SCM symbol
= scm_intern_obarray_soft (name
, strlen (name
), scm_symhash
, 0);
434 SCM vcell
= scm_sym2vcell (SCM_CAR (symbol
),
435 SCM_CDR (scm_top_level_lookup_closure_var
),
437 if (SCM_FALSEP (vcell
))
438 return SCM_UNDEFINED
;
439 return SCM_CDR (vcell
);
442 SCM_PROC(s_symbol_p
, "symbol?", 1, 0, 0, scm_symbol_p
);
448 if SCM_IMP(x
) return SCM_BOOL_F
;
449 return SCM_SYMBOLP(x
) ? SCM_BOOL_T
: SCM_BOOL_F
;
452 SCM_PROC(s_symbol_to_string
, "symbol->string", 1, 0, 0, scm_symbol_to_string
);
455 scm_symbol_to_string(s
)
458 SCM_ASSERT(SCM_NIMP(s
) && SCM_SYMBOLP(s
), s
, SCM_ARG1
, s_symbol_to_string
);
459 return scm_makfromstr(SCM_CHARS(s
), (scm_sizet
)SCM_LENGTH(s
), 0);
463 SCM_PROC(s_string_to_symbol
, "string->symbol", 1, 0, 0, scm_string_to_symbol
);
466 scm_string_to_symbol(s
)
472 SCM_ASSERT(SCM_NIMP(s
) && SCM_ROSTRINGP(s
), s
, SCM_ARG1
, s_string_to_symbol
);
473 vcell
= scm_intern(SCM_ROCHARS(s
), (scm_sizet
)SCM_LENGTH(s
));
474 answer
= SCM_CAR (vcell
);
479 SCM_PROC(s_string_to_obarray_symbol
, "string->obarray-symbol", 2, 1, 0, scm_string_to_obarray_symbol
);
482 scm_string_to_obarray_symbol(o
, s
, softp
)
491 SCM_ASSERT(SCM_NIMP(s
) && SCM_ROSTRINGP(s
), s
, SCM_ARG2
,
492 s_string_to_obarray_symbol
);
493 SCM_ASSERT((o
== SCM_BOOL_F
)
495 || (SCM_NIMP(o
) && SCM_VECTORP(o
)),
498 s_string_to_obarray_symbol
);
500 softness
= ((softp
!= SCM_UNDEFINED
) && (softp
!= SCM_BOOL_F
));
501 /* iron out some screwy calling conventions */
504 else if (o
== SCM_BOOL_T
)
507 vcell
= scm_intern_obarray_soft (SCM_ROCHARS(s
),
508 (scm_sizet
)SCM_ROLENGTH(s
),
511 if (vcell
== SCM_BOOL_F
)
513 answer
= SCM_CAR (vcell
);
517 SCM_PROC(s_intern_symbol
, "intern-symbol", 2, 0, 0, scm_intern_symbol
);
520 scm_intern_symbol(o
, s
)
525 SCM_ASSERT(SCM_NIMP(s
) && SCM_SYMBOLP(s
), s
, SCM_ARG2
, s_intern_symbol
);
528 SCM_ASSERT(SCM_NIMP(o
) && SCM_VECTORP(o
), o
, SCM_ARG1
, s_intern_symbol
);
529 hval
= scm_strhash (SCM_UCHARS (s
), SCM_LENGTH (s
), SCM_LENGTH(o
));
530 /* If the symbol is already interned, simply return. */
535 for (lsym
= SCM_VELTS (o
)[hval
];
537 lsym
= SCM_CDR (lsym
))
539 sym
= SCM_CAR (lsym
);
540 if (SCM_CAR (sym
) == s
)
543 return SCM_UNSPECIFIED
;
546 SCM_VELTS (o
)[hval
] =
547 scm_acons (s
, SCM_UNDEFINED
, SCM_VELTS (o
)[hval
]);
550 return SCM_UNSPECIFIED
;
553 SCM_PROC(s_unintern_symbol
, "unintern-symbol", 2, 0, 0, scm_unintern_symbol
);
556 scm_unintern_symbol(o
, s
)
561 SCM_ASSERT(SCM_NIMP(s
) && SCM_SYMBOLP(s
), s
, SCM_ARG2
, s_unintern_symbol
);
564 SCM_ASSERT(SCM_NIMP(o
) && SCM_VECTORP(o
), o
, SCM_ARG1
, s_unintern_symbol
);
565 hval
= scm_strhash (SCM_UCHARS (s
), SCM_LENGTH (s
), SCM_LENGTH(o
));
571 for (lsym
= SCM_VELTS (o
)[hval
], lsym_follow
= SCM_BOOL_F
;
573 lsym_follow
= lsym
, lsym
= SCM_CDR (lsym
))
575 sym
= SCM_CAR (lsym
);
576 if (SCM_CAR (sym
) == s
)
578 /* Found the symbol to unintern. */
579 if (lsym_follow
== SCM_BOOL_F
)
580 SCM_VELTS(o
)[hval
] = lsym
;
582 SCM_SETCDR (lsym_follow
, SCM_CDR(lsym
));
592 SCM_PROC(s_symbol_binding
, "symbol-binding", 2, 0, 0, scm_symbol_binding
);
595 scm_symbol_binding (o
, s
)
600 SCM_ASSERT(SCM_NIMP(s
) && SCM_SYMBOLP(s
), s
, SCM_ARG2
, s_symbol_binding
);
603 SCM_ASSERT(SCM_NIMP(o
) && SCM_VECTORP(o
), o
, SCM_ARG1
, s_symbol_binding
);
604 vcell
= scm_sym2ovcell (s
, o
);
605 return SCM_CDR(vcell
);
609 SCM_PROC(s_symbol_interned_p
, "symbol-interned?", 2, 0, 0, scm_symbol_interned_p
);
612 scm_symbol_interned_p (o
, s
)
617 SCM_ASSERT(SCM_NIMP(s
) && SCM_SYMBOLP(s
), s
, SCM_ARG2
, s_symbol_interned_p
);
620 SCM_ASSERT(SCM_NIMP(o
) && SCM_VECTORP(o
), o
, SCM_ARG1
, s_symbol_interned_p
);
621 vcell
= scm_sym2ovcell_soft (s
, o
);
622 if (SCM_IMP(vcell
) && (o
== scm_symhash
))
623 vcell
= scm_sym2ovcell_soft (s
, scm_weak_symhash
);
624 return (SCM_NIMP(vcell
)
630 SCM_PROC(s_symbol_bound_p
, "symbol-bound?", 2, 0, 0, scm_symbol_bound_p
);
633 scm_symbol_bound_p (o
, s
)
638 SCM_ASSERT(SCM_NIMP(s
) && SCM_SYMBOLP(s
), s
, SCM_ARG2
, s_symbol_bound_p
);
641 SCM_ASSERT(SCM_NIMP(o
) && SCM_VECTORP(o
), o
, SCM_ARG1
, s_symbol_bound_p
);
642 vcell
= scm_sym2ovcell_soft (s
, o
);
643 return (( SCM_NIMP(vcell
)
644 && (SCM_CDR(vcell
) != SCM_UNDEFINED
))
650 SCM_PROC(s_symbol_set_x
, "symbol-set!", 3, 0, 0, scm_symbol_set_x
);
653 scm_symbol_set_x (o
, s
, v
)
659 SCM_ASSERT(SCM_NIMP(s
) && SCM_SYMBOLP(s
), s
, SCM_ARG2
, s_symbol_set_x
);
662 SCM_ASSERT(SCM_NIMP(o
) && SCM_VECTORP(o
), o
, SCM_ARG1
, s_symbol_set_x
);
663 vcell
= scm_sym2ovcell (s
, o
);
664 SCM_SETCDR (vcell
, v
);
665 return SCM_UNSPECIFIED
;
673 string
= scm_makfromstr (SCM_CHARS (s
), SCM_LENGTH (s
), SCM_SYMBOL_SLOTS
);
674 SCM_SETCHARS (s
, SCM_CHARS (string
));
675 SCM_SETLENGTH (s
, SCM_LENGTH (s
), scm_tc7_msymbol
);
676 SCM_SETCDR (string
, SCM_EOL
);
677 SCM_SETCAR (string
, SCM_EOL
);
678 SCM_SYMBOL_PROPS (s
) = SCM_EOL
;
679 /* If it's a tc7_ssymbol, it comes from scm_symhash */
680 SCM_SYMBOL_HASH (s
) = scm_strhash (SCM_UCHARS (s
),
681 (scm_sizet
) SCM_LENGTH (s
),
682 SCM_LENGTH (scm_symhash
));
686 SCM_PROC(s_symbol_fref
, "symbol-fref", 1, 0, 0, scm_symbol_fref
);
692 SCM_ASSERT(SCM_NIMP(s
) && SCM_SYMBOLP(s
), s
, SCM_ARG1
, s_symbol_fref
);
694 if (SCM_TYP7(s
) == scm_tc7_ssymbol
)
697 return SCM_SYMBOL_FUNC (s
);
701 SCM_PROC(s_symbol_pref
, "symbol-pref", 1, 0, 0, scm_symbol_pref
);
707 SCM_ASSERT(SCM_NIMP(s
) && SCM_SYMBOLP(s
), s
, SCM_ARG1
, s_symbol_pref
);
709 if (SCM_TYP7(s
) == scm_tc7_ssymbol
)
712 return SCM_SYMBOL_PROPS (s
);
716 SCM_PROC(s_symbol_fset_x
, "symbol-fset!", 2, 0, 0, scm_symbol_fset_x
);
719 scm_symbol_fset_x (s
, val
)
723 SCM_ASSERT(SCM_NIMP(s
) && SCM_SYMBOLP(s
), s
, SCM_ARG1
, s_symbol_fset_x
);
725 if (SCM_TYP7(s
) == scm_tc7_ssymbol
)
728 SCM_SYMBOL_FUNC (s
) = val
;
729 return SCM_UNSPECIFIED
;
733 SCM_PROC(s_symbol_pset_x
, "symbol-pset!", 2, 0, 0, scm_symbol_pset_x
);
736 scm_symbol_pset_x (s
, val
)
740 SCM_ASSERT(SCM_NIMP(s
) && SCM_SYMBOLP(s
), s
, SCM_ARG1
, s_symbol_pset_x
);
742 if (SCM_TYP7(s
) == scm_tc7_ssymbol
)
744 SCM_SYMBOL_PROPS (s
) = val
;
746 return SCM_UNSPECIFIED
;
750 SCM_PROC(s_symbol_hash
, "symbol-hash", 1, 0, 0, scm_symbol_hash
);
756 SCM_ASSERT(SCM_NIMP(s
) && SCM_SYMBOLP(s
), s
, SCM_ARG1
, s_symbol_hash
);
757 if (SCM_TYP7(s
) == scm_tc7_ssymbol
)
759 return SCM_MAKINUM ((unsigned long)s
^ SCM_SYMBOL_HASH (s
));
763 static void copy_and_prune_obarray
SCM_P ((SCM from
, SCM to
));
766 copy_and_prune_obarray (from
, to
)
771 int length
= SCM_LENGTH (from
);
772 for (i
= 0; i
< length
; ++i
)
774 SCM head
= SCM_VELTS (from
)[i
]; /* GC protection */
778 while (SCM_NIMP (ls
))
780 if (!SCM_UNBNDP (SCM_CDAR (ls
)))
782 *lloc
= scm_cons (SCM_CAR (ls
), SCM_EOL
);
783 lloc
= SCM_CDRLOC (*lloc
);
787 SCM_VELTS (to
)[i
] = res
;
792 SCM_PROC(s_builtin_bindings
, "builtin-bindings", 0, 0, 0, scm_builtin_bindings
);
795 scm_builtin_bindings ()
797 int length
= SCM_LENGTH (scm_symhash
);
798 SCM obarray
= scm_make_vector (SCM_MAKINUM (length
), SCM_EOL
, SCM_UNDEFINED
);
799 copy_and_prune_obarray (scm_symhash
, obarray
);
804 SCM_PROC(s_builtin_weak_bindings
, "builtin-weak-bindings", 0, 0, 0, scm_builtin_weak_bindings
);
807 scm_builtin_weak_bindings ()
809 int length
= SCM_LENGTH (scm_weak_symhash
);
810 SCM obarray
= scm_make_doubly_weak_hash_table (SCM_MAKINUM (length
));
811 copy_and_prune_obarray (scm_weak_symhash
, obarray
);
815 static int gensym_counter
;
816 static SCM gensym_prefix
;
819 SCM_PROC (s_gensym
, "gensym", 0, 2, 0, scm_gensym
);
822 scm_gensym (name
, obarray
)
827 if (SCM_UNBNDP (name
))
828 name
= gensym_prefix
;
830 SCM_ASSERT (SCM_ROSTRINGP (name
), name
, SCM_ARG1
, s_gensym
);
832 if (SCM_UNBNDP (obarray
))
834 obarray
= SCM_BOOL_F
;
838 SCM_ASSERT (SCM_NIMP (obarray
)
839 && (SCM_VECTORP (obarray
) || SCM_WVECTP (obarray
)),
843 while (scm_string_to_obarray_symbol (obarray
, new, SCM_BOOL_T
)
846 new = scm_string_append
848 scm_number_to_string (SCM_MAKINUM (gensym_counter
++),
851 return scm_string_to_obarray_symbol (obarray
, new, SCM_BOOL_F
);
858 gensym_prefix
= scm_permanent_object (scm_makfrom0str ("%%gensym"));