1 /* -*- tab-width:4; -*- */
2 /*
3  * Symbol and Keywords handling
4  *
5  *
6  * Note: code to print and mark symbol is inlined in scm_gc_mark and scm_write
7  *
8  */
9 
10 #include "s.h"
11 
12 /*-- hashes */
13 SOBJ scm_symbol_hash;			/* hash for symbols */
14 SOBJ scm_keyword_hash;			/* hash for keywords */
15 int  scm_keyword_write_mode;	/* write mode for symbols */
16 char *scm_keyword_write_prefix;
17 char *scm_keyword_write_suffix;
18 
19 /*-- make a symbol */
20 
scm_mksymbol2(SOBJ atom,SOBJ value)21 SOBJ scm_mksymbol2(SOBJ atom, SOBJ value)
22 {
23   SOBJ new = scm_newcell(SOBJ_T_SYMBOL);
24   SCM_SYM_NAME(new)  = atom;
25   SCM_SYM_VALUE(new) = value;
26   return(new);
27 }
28 
scm_mksymbol(char * str)29 SOBJ scm_mksymbol(char *str)
30 {
31   return(scm_mksymbol2(scm_mkatom(str), scm_unbound));
32 }
33 
scm_mkkeyword2(SOBJ atom,SOBJ dummy)34 SOBJ scm_mkkeyword2(SOBJ atom, SOBJ dummy)
35 {
36   SOBJ new = scm_newcell(SOBJ_T_KEYWORD);
37   SCM_KEYW_NAME(new) = atom;
38   return(new);
39 }
40 
scm_mkkeyword(char * str)41 SOBJ scm_mkkeyword(char *str)
42 {
43   return(scm_mkkeyword2(scm_mkatom(str), NULL));
44 }
45 
scm_symbol_mark(SOBJ obj)46 void scm_symbol_mark(SOBJ obj)
47 {
48   scm_gc_mark(SCM_SYM_NAME(obj));
49   scm_gc_mark(SCM_SYM_VALUE(obj));
50 }
51 
scm_symbol_sweep(SOBJ obj)52 void scm_symbol_sweep(SOBJ obj)
53 {
54 }
55 
56 /*-- search for a symbol */
scm_symsearch(char * str)57 SOBJ scm_symsearch(char *str)
58 {
59   SOBJ obj = scm_hash_search(scm_symbol_hash, scm_mkatom(str));
60   return( (obj == scm_undefined) ? NULL : obj );
61 }
62 
63 /*-- add a new symbol: no duplicate checks are done */
64 
scm_atom_hash_complete(SOBJ hash,SOBJ atom,SOBJ (* create)())65 SOBJ scm_atom_hash_complete(SOBJ hash, SOBJ atom, SOBJ (*create)())
66 {
67   int i;
68   SCM_Hash *h;
69   SOBJ p, e;
70 
71   h = SCM_HASH(hash);
72   i = scm_hash_code(h, atom);
73   for (p = h->hash[i]; p; p = SCM_CDR(p)) {
74 	e = SCM_CAR(p);
75 	if (SCM_SYM_NAME(e) == atom) return(e);
76   }
77   e = (*create)(atom, scm_unbound);
78   h->hash[i] = scm_cons(e, h->hash[i]);
79   h->nkeys++;
80 
81   if (h->nkeys >= h->maxkeys) { scm_rebuild_hash(hash); }
82   return(e);
83 }
84 
scm_symadd(char * str,SOBJ value)85 SOBJ scm_symadd(char *str, SOBJ value)
86 {
87   SOBJ node;
88   SOBJ atom = scm_mkatom(str);
89   node = scm_hash_set(scm_symbol_hash, atom, value);
90   node = scm_hash_search(scm_symbol_hash, atom);
91 #ifdef DEBUG
92   scm_puts("scm_symadd: ");  scm_cprint(node);
93 #endif
94   return(node);
95 }
96 
scm_sym_clone(SOBJ sym)97 SOBJ scm_sym_clone(SOBJ sym)
98 {
99   return(scm_atom_hash_complete(scm_symbol_hash,
100 								SCM_SYM_NAME(sym),
101 								scm_mksymbol2));
102 }
103 
104 /****************************************************************
105  * Keyword routines
106  ****************************************************************/
scm_keyword_add(char * str)107 SOBJ scm_keyword_add(char *str)
108 {
109   return(scm_atom_hash_complete(scm_keyword_hash,
110 								scm_mkatom(str),
111 								scm_mkkeyword2));
112 }
113 
scm_keywordp(SOBJ obj)114 SOBJ scm_keywordp(SOBJ obj)
115 {
116   return(SCM_MKBOOL(SCM_OBJTYPE(obj) == SOBJ_T_KEYWORD));
117 }
118 
scm_keyword_to_string(SOBJ obj)119 SOBJ scm_keyword_to_string(SOBJ obj)
120 {
121   if (!SCM_KEYWORDP(obj)) 	SCM_ERR("keyword->string: bad keyword", obj);
122   return(scm_atom_to_string(SCM_KEYW_NAME(obj)));
123 }
124 
scm_string_to_keyword(SOBJ obj)125 SOBJ scm_string_to_keyword(SOBJ obj)
126 {
127   if (!SCM_STRINGP(obj)) 	SCM_ERR("string->keyword: bad string", obj);
128   return(scm_keyword_add(SCM_STR_VALUE(obj)));
129 }
130 
scm_get_keyword(SOBJ keyw,SOBJ list,SOBJ default_value)131 SOBJ scm_get_keyword(SOBJ keyw, SOBJ list, SOBJ default_value)
132 {
133   if (!SCM_KEYWORDP(keyw))	SCM_ERR("get-keyword: bad keyword", keyw);
134 
135   while(list) {
136 	if (!SCM_PAIRP(list))	goto bad_list;
137 
138 	if (!SCM_KEYWORDP(SCM_CAR(list)))
139 		SCM_ERR("get-keyword: bad keyword", SCM_CAR(list));
140 
141 	if (SCM_KEYW_NAME(SCM_CAR(list)) == SCM_KEYW_NAME(keyw)) {
142 	  list = SCM_CDR(list);
143 	  if (!SCM_PAIRP(list))	SCM_ERR("get-keyword: bad value", list);
144 	  return(SCM_CAR(list));
145 	}
146 	/* jump over value and get next potential keyword */
147 	list = SCM_CDR(list);  if (!SCM_PAIRP(list))  goto bad_list;
148 	list = SCM_CDR(list);
149   }
150   return(default_value);
151 
152  bad_list:
153   SCM_ERR("get-keyword: bad list", list);
154   return(NULL);
155 }
156 
scm_init_symbol_hash()157 void scm_init_symbol_hash()
158 {
159   scm_symbol_hash = scm_mkhash(SCM_HASH_T_SYMBOL);
160   scm_gc_protect(&scm_symbol_hash);
161 
162   scm_keyword_hash= scm_mkhash(SCM_HASH_T_SYMBOL);
163   scm_gc_protect(&scm_keyword_hash);
164 }
165 
166 /*E* (keyword-display-type NUMBER) => NUMBER */
167 /*D* Changes the way of keyword display. When NUMBER is 0, the
168   keywords are displayed prefixed by ':', when NUMBER is 1 they are
169   prefixed with '#!' and when NUMBER is 2 they are suffixed with ':' */
scm_keyword_display_type(SOBJ x)170 SOBJ scm_keyword_display_type(SOBJ x)
171 {
172   int mode = SCM_INUM(x);
173   switch(mode) {
174   case SCM_KEYW_WRITE_DEFLT:
175 	scm_keyword_write_prefix = ":";
176 	scm_keyword_write_suffix = "";
177 	break;
178   case SCM_KEYW_WRITE_DSSL:
179 	scm_keyword_write_prefix = "#!";
180 	scm_keyword_write_suffix = "";
181 	break;
182   case SCM_KEYW_WRITE_OTHER:
183 	scm_keyword_write_prefix = "";
184 	scm_keyword_write_suffix = ":";
185 	break;
186   default:
187 	mode = SCM_KEYW_WRITE_DEFLT;
188   }
189   scm_keyword_write_mode = mode;
190   return(x);
191 }
192 
193 /*E* (gensym [PREFIX]) => SYMBOL */
194 /*D* Returns a new symbol which is guaranted to be unique (during this
195   scheme session). */
scm_gensym(int nargs,SOBJ * arg)196 SOBJ scm_gensym(int nargs, SOBJ *arg)
197 {
198   char *prefix;
199   char buf[128];
200   static int count;
201   SOBJ new;
202 
203   if (nargs != 0) {
204 	scm_puts("WARNING: gensym ignores prefix argument");
205   }
206   prefix = SCM_GENSYM_PREFIX;
207   sprintf(buf, "%s%d", prefix, count++);
208   new = scm_newcell(SOBJ_T_ATOM);
209   SCM_ATOM_NAME(new) = scm_must_strdup(buf);
210   SCM_ATOM_NEXT(new) = NULL;
211   return(scm_mksymbol2(new, scm_unbound));
212 }
213 
214 /*E* (make-symbol NAME) => SYMBOL */
215 /*D* Create an unbound symbol. */
scm_make_symbol(SOBJ name)216 SOBJ scm_make_symbol(SOBJ name)
217 {
218   if (!SCM_ATOMP(name))	SCM_ERR("bad symbol", name);
219   return(scm_mksymbol2(name, scm_unbound));
220 }
221 
222 /*E* (symbol-name SYM) => NAME */
223 /*D* Returns the name associated to symbol SYM. NAME is an atom.*/
scm_symbol_name(SOBJ x)224 SOBJ scm_symbol_name(SOBJ x)
225 {
226   if (!SCM_SYMBOLP(x)) 	SCM_ERR("bad symbol", x);
227   return(SCM_SYM_NAME(x));
228 }
229 
230 /*E* (symbol-value SYM) => VALUE */
231 /*D* Returns the value associated to symbol SYM. VALUE is any scheme
232   object. */
scm_symbol_value(SOBJ x)233 SOBJ scm_symbol_value(SOBJ x)
234 {
235   if (!SCM_SYMBOLP(x)) 	SCM_ERR("bad symbol", x);
236   return(SCM_SYM_VALUE(x));
237 }
238 
scm_init_symbol()239 void scm_init_symbol()
240 {
241   scm_keyword_write_mode = SCM_KEYW_WRITE_DEFLT;
242   scm_keyword_write_prefix = ":";
243   scm_keyword_write_suffix = "";
244 
245   scm_add_cprim("keyword-display-type", scm_keyword_display_type, 1);
246   scm_add_cprim("gensym",				scm_gensym,			-1);
247   scm_add_cprim("make-symbol",			scm_make_symbol,	1);
248   scm_add_cprim("symbol-name",			scm_symbol_name,	1);
249   scm_add_cprim("symbol-value",			scm_symbol_value,	1);
250 }
251