Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 346 lines (298 sloc) 7.855 kB
19f18d3 a new Symbol class, unicode-aware + refactored/cleaned symbol generation
Laurent Sansonetti authored
1 /*
2 * MacRuby Symbols.
3 *
4 * This file is covered by the Ruby license. See COPYING for more details.
5 *
6 * Copyright (C) 2010, Apple Inc. All rights reserved.
7 */
8
9 #include <wctype.h>
10
11 #include "ruby.h"
12 #include "ruby/encoding.h"
13 #include "encoding.h"
14 #include "symbol.h"
15 #include "ruby/node.h"
16 #include "vm.h"
17
18 VALUE rb_cSymbol;
19
20 static CFMutableDictionaryRef sym_id = NULL, id_str = NULL;
21 static long last_id = 0;
22
23 typedef struct {
24 VALUE klass;
25 rb_str_t *str;
26 ID id;
27 } rb_sym_t;
28
29 #define RSYM(obj) ((rb_sym_t *)(obj))
30
31 static rb_sym_t *
32 sym_alloc(rb_str_t *str, ID id)
33 {
34 rb_sym_t *sym = (rb_sym_t *)malloc(sizeof(rb_sym_t));
35 assert(rb_cSymbol != 0);
36 sym->klass = rb_cSymbol;
37 GC_RETAIN(str); // never released
38 sym->str = str;
39 sym->id = id;
40 return sym;
41 }
42
43 ID
44 rb_intern_str(VALUE str)
45 {
4ee0afb some misc fixes/cleanup
Laurent Sansonetti authored
46 const unsigned long name_hash = rb_str_hash(str);
19f18d3 a new Symbol class, unicode-aware + refactored/cleaned symbol generation
Laurent Sansonetti authored
47 ID id = (ID)CFDictionaryGetValue(sym_id, (const void *)name_hash);
48 if (id != 0) {
4ee0afb some misc fixes/cleanup
Laurent Sansonetti authored
49 return id;
19f18d3 a new Symbol class, unicode-aware + refactored/cleaned symbol generation
Laurent Sansonetti authored
50 }
51
52 rb_sym_t *sym = NULL;
53
4ee0afb some misc fixes/cleanup
Laurent Sansonetti authored
54 const long chars_len = rb_str_chars_len(str);
55 if (chars_len > 0) {
56 UChar c = rb_str_get_uchar(str, 0);
57 switch (c) {
58 case '$':
59 id = ID_GLOBAL;
60 break;
61
62 case '@':
63 if (chars_len > 1 && rb_str_get_uchar(str, 1) == '@') {
64 id = ID_CLASS;
19f18d3 a new Symbol class, unicode-aware + refactored/cleaned symbol generation
Laurent Sansonetti authored
65 }
4ee0afb some misc fixes/cleanup
Laurent Sansonetti authored
66 else {
67 id = ID_INSTANCE;
68 }
69 break;
70
71 default:
72 if (chars_len > 1
73 && rb_str_get_uchar(str, chars_len - 1) == '=') {
74 // Attribute assignment.
75 id = rb_intern_str(rb_str_substr(str, 0, chars_len - 1));
76 if (!is_attrset_id(id)) {
77 id = rb_id_attrset(id);
78 goto id_register;
79 }
80 id = ID_ATTRSET;
81 }
82 else if (iswupper(c)) {
83 id = ID_CONST;
84 }
85 else {
86 id = ID_LOCAL;
87 }
88 break;
89 }
19f18d3 a new Symbol class, unicode-aware + refactored/cleaned symbol generation
Laurent Sansonetti authored
90 }
91
92 id |= ++last_id << ID_SCOPE_SHIFT;
93
94 id_register:
95 //printf("register %s hash %ld id %ld\n", RSTRING_PTR(str), name_hash, id);
4ee0afb some misc fixes/cleanup
Laurent Sansonetti authored
96 assert(IS_RSTR(str));
19f18d3 a new Symbol class, unicode-aware + refactored/cleaned symbol generation
Laurent Sansonetti authored
97 sym = sym_alloc(RSTR(str), id);
98 CFDictionarySetValue(sym_id, (const void *)name_hash, (const void *)id);
99 CFDictionarySetValue(id_str, (const void *)id, (const void *)sym);
100
101 return id;
102 }
103
104 VALUE
105 rb_id2str(ID id)
106 {
107 VALUE sym = (VALUE)CFDictionaryGetValue(id_str, (const void *)id);
108 if (sym != 0) {
109 //printf("lookup %ld -> %s\n", id, rb_sym2name(sym));
110 return sym;
111 }
112
113 if (is_attrset_id(id)) {
114 // Attribute assignment.
115 ID id2 = (id & ~ID_SCOPE_MASK) | ID_LOCAL;
116
117 while ((sym = rb_id2str(id2)) == 0) {
118 if (!is_local_id(id2)) {
119 //printf("lookup %ld -> FAIL\n", id);
120 return 0;
121 }
122 id2 = (id & ~ID_SCOPE_MASK) | ID_CONST;
123 }
124
125 VALUE str = rb_str_dup((VALUE)RSYM(sym)->str);
126 rb_str_cat(str, "=", 1);
127 rb_intern_str(str);
128
129 // Retry one more time.
130 sym = (VALUE)CFDictionaryGetValue(id_str, (const void *)id);
131 if (sym != 0) {
132 //printf("lookup %ld -> %s\n", id, rb_sym2name(sym));
133 return sym;
134 }
135 }
136 //printf("lookup %ld -> FAIL\n", id);
137 return 0;
138 }
139
140 ID
141 rb_intern3(const char *name, long len, rb_encoding *enc)
142 {
143 VALUE str = rb_enc_str_new(name, len, enc);
144 return rb_intern_str(str);
145 }
146
147 ID
148 rb_intern2(const char *name, long len)
149 {
150 return rb_intern_str(rb_str_new(name, len));
151 }
152
153 ID
154 rb_intern(const char *name)
155 {
156 return rb_intern_str(rb_str_new2(name));
157 }
158
159 ID
160 rb_sym2id(VALUE sym)
161 {
162 return RSYM(sym)->id;
163 }
164
165 VALUE
166 rb_name2sym(const char *name)
167 {
168 return rb_id2str(rb_intern(name));
169 }
170
171 VALUE
172 rb_sym2str(VALUE sym)
173 {
174 return (VALUE)RSYM(sym)->str;
175 }
176
177 VALUE
178 rb_sym_to_s(VALUE sym)
179 {
180 return rb_str_dup(rb_sym2str(sym));
181 }
182
183 const char *
184 rb_sym2name(VALUE sym)
185 {
186 return RSTRING_PTR(RSYM(sym)->str);
187 }
188
189 /*
190 * call-seq:
191 * Symbol.all_symbols => array
192 *
193 * Returns an array of all the symbols currently in Ruby's symbol
194 * table.
195 *
196 * Symbol.all_symbols.size #=> 903
197 * Symbol.all_symbols[1,20] #=> [:floor, :ARGV, :Binding, :symlink,
198 * :chown, :EOFError, :$;, :String,
199 * :LOCK_SH, :"setuid?", :$<,
200 * :default_proc, :compact, :extend,
201 * :Tms, :getwd, :$=, :ThreadGroup,
202 * :wait2, :$>]
203 */
204
205 static VALUE
206 rsym_all_symbols(VALUE klass, SEL sel)
207 {
208 VALUE ary = rb_ary_new();
209 const long count = CFDictionaryGetCount(id_str);
210 if (count >= 0) {
211 const void **values = (const void **)malloc(sizeof(void *) * count);
212 CFDictionaryGetKeysAndValues(id_str, NULL, values);
213 for (long i = 0; i < count; i++) {
214 rb_ary_push(ary, (VALUE)values[i]);
215 }
216 free(values);
217 }
218 return ary;
219 }
220
221 void
222 Init_PreSymbol(void)
223 {
224 sym_id = CFDictionaryCreateMutable(NULL, 0, NULL, NULL);
225 id_str = CFDictionaryCreateMutable(NULL, 0, NULL, NULL);
226 last_id = 1000;
227
228 // Pre-register parser symbols.
229 for (int i = 0; rb_op_tbl[i].token != 0; i++) {
230 ID id = rb_op_tbl[i].token;
4ee0afb some misc fixes/cleanup
Laurent Sansonetti authored
231 VALUE str = rb_str_new2(rb_op_tbl[i].name);
19f18d3 a new Symbol class, unicode-aware + refactored/cleaned symbol generation
Laurent Sansonetti authored
232 rb_sym_t *sym = sym_alloc(RSTR(str), id);
4ee0afb some misc fixes/cleanup
Laurent Sansonetti authored
233 unsigned long name_hash = rb_str_hash(str);
19f18d3 a new Symbol class, unicode-aware + refactored/cleaned symbol generation
Laurent Sansonetti authored
234
235 //printf("pre-register %s hash %ld id %ld\n", RSTRING_PTR(str), name_hash, id);
236
237 CFDictionarySetValue(sym_id, (const void *)name_hash, (const void *)id);
238 CFDictionarySetValue(id_str, (const void *)id, (const void *)sym);
239 }
240 }
241
242 /*
243 * call-seq:
244 * sym == obj => true or false
245 *
246 * Equality---If <i>sym</i> and <i>obj</i> are exactly the same
247 * symbol, returns <code>true</code>. Otherwise, compares them
248 * as strings.
249 */
250
251 static VALUE
252 rsym_equal(VALUE sym, SEL sel, VALUE other)
253 {
254 return sym == other ? Qtrue : Qfalse;
255 }
256
257 /*
258 * call-seq:
259 * sym.inspect => string
260 *
261 * Returns the representation of <i>sym</i> as a symbol literal.
262 *
263 * :fred.inspect #=> ":fred"
264 */
265
266 static VALUE
267 rsym_inspect(VALUE sym, SEL sel)
268 {
269 VALUE str = rb_str_new2(":");
270 rb_str_concat(str, str_inspect(RSYM(sym)->str, true));
271 return str;
272 }
273
274 /*
275 * call-seq:
276 * sym.to_proc
277 *
278 * Returns a _Proc_ object which respond to the given method by _sym_.
279 *
280 * (1..3).collect(&:to_s) #=> ["1", "2", "3"]
281 */
282
283 static VALUE
284 rsym_to_proc(VALUE sym, SEL sel)
285 {
286 SEL msel = sel_registerName(rb_id2name(SYM2ID(sym)));
287 rb_vm_block_t *b = rb_vm_create_block_calling_sel(msel);
288 return rb_proc_alloc_with_block(rb_cProc, b);
289 }
290
291 /*
292 * call-seq:
293 * sym.id2name => string
294 * sym.to_s => string
295 *
296 * Returns the name or string corresponding to <i>sym</i>.
297 *
298 * :fred.id2name #=> "fred"
299 */
300
301 static VALUE
302 rsym_to_s(VALUE sym, SEL sel)
303 {
304 return rb_sym_to_s(sym);
305 }
306
307 /*
308 * call-seq:
309 * sym.to_sym => sym
310 * sym.intern => sym
311 *
312 * In general, <code>to_sym</code> returns the <code>Symbol</code>
313 * corresponding to an object. As <i>sym</i> is already a symbol,
314 * <code>self</code> is returned in this case.
315 */
316
317 static VALUE
318 rsym_to_sym(VALUE sym, SEL sel)
319 {
320 return sym;
321 }
322
323 void
324 Init_Symbol(void)
325 {
326 // rb_cSymbol is defined earlier in Init_PreVM().
327 rb_set_class_path(rb_cSymbol, rb_cObject, "Symbol");
328 rb_const_set(rb_cObject, rb_intern("Symbol"), rb_cSymbol);
329
330 rb_undef_alloc_func(rb_cSymbol);
331 rb_undef_method(*(VALUE *)rb_cSymbol, "new");
332 rb_objc_define_method(*(VALUE *)rb_cSymbol, "all_symbols",
333 rsym_all_symbols, 0);
334
335 rb_objc_define_method(rb_cSymbol, "==", rsym_equal, 1);
336 rb_objc_define_method(rb_cSymbol, "eql?", rsym_equal, 1);
337 //rb_objc_define_method(rb_cSymbol, "<=>", rsym_cmp, 1);
338 rb_objc_define_method(rb_cSymbol, "inspect", rsym_inspect, 0);
339 rb_objc_define_method(rb_cSymbol, "to_proc", rsym_to_proc, 0);
340 rb_objc_define_method(rb_cSymbol, "to_s", rsym_to_s, 0);
341 rb_objc_define_method(rb_cSymbol, "id2name", rsym_to_s, 0);
342 rb_objc_define_method(rb_cSymbol, "description", rsym_to_s, 0);
343 rb_objc_define_method(rb_cSymbol, "intern", rsym_to_sym, 0);
344 rb_objc_define_method(rb_cSymbol, "to_sym", rsym_to_sym, 0);
345 }
Something went wrong with that request. Please try again.