mbed I/F binding for mruby
Dependents: mruby_mbed_web mirb_mbed
symbol.c
00001 /* 00002 ** symbol.c - Symbol class 00003 ** 00004 ** See Copyright Notice in mruby.h 00005 */ 00006 00007 #include <ctype.h> 00008 #include <limits.h> 00009 #include <string.h> 00010 #include "mruby.h" 00011 #include "mruby/khash.h" 00012 #include "mruby/string.h" 00013 #include "mruby/dump.h" 00014 00015 /* ------------------------------------------------------ */ 00016 typedef struct symbol_name { 00017 mrb_bool lit : 1; 00018 uint16_t len; 00019 const char *name; 00020 } symbol_name; 00021 00022 static inline khint_t 00023 sym_hash_func(mrb_state *mrb, mrb_sym s) 00024 { 00025 khint_t h = 0; 00026 size_t i, len = mrb->symtbl[s].len; 00027 const char *p = mrb->symtbl[s].name; 00028 00029 for (i=0; i<len; i++) { 00030 h = (h << 5) - h + *p++; 00031 } 00032 return h; 00033 } 00034 #define sym_hash_equal(mrb,a, b) (mrb->symtbl[a].len == mrb->symtbl[b].len && memcmp(mrb->symtbl[a].name, mrb->symtbl[b].name, mrb->symtbl[a].len) == 0) 00035 00036 KHASH_DECLARE(n2s, mrb_sym, mrb_sym, FALSE) 00037 KHASH_DEFINE (n2s, mrb_sym, mrb_sym, FALSE, sym_hash_func, sym_hash_equal) 00038 /* ------------------------------------------------------ */ 00039 00040 static void 00041 sym_validate_len(mrb_state *mrb, size_t len) 00042 { 00043 if (len >= RITE_LV_NULL_MARK) { 00044 mrb_raise(mrb, E_ARGUMENT_ERROR, "symbol length too long"); 00045 } 00046 } 00047 00048 static mrb_sym 00049 sym_intern(mrb_state *mrb, const char *name, size_t len, mrb_bool lit) 00050 { 00051 khash_t(n2s) *h = mrb->name2sym; 00052 symbol_name *sname = mrb->symtbl; /* symtbl[0] for working memory */ 00053 khiter_t k; 00054 mrb_sym sym; 00055 char *p; 00056 00057 sym_validate_len(mrb, len); 00058 if (sname) { 00059 sname->lit = lit; 00060 sname->len = (uint16_t)len; 00061 sname->name = name; 00062 k = kh_get(n2s, mrb, h, 0); 00063 if (k != kh_end(h)) 00064 return kh_key(h, k); 00065 } 00066 00067 /* registering a new symbol */ 00068 sym = ++mrb->symidx; 00069 if (mrb->symcapa < sym) { 00070 if (mrb->symcapa == 0) mrb->symcapa = 100; 00071 else mrb->symcapa = (size_t)(mrb->symcapa * 1.2); 00072 mrb->symtbl = (symbol_name*)mrb_realloc(mrb, mrb->symtbl, sizeof(symbol_name)*(mrb->symcapa+1)); 00073 } 00074 sname = &mrb->symtbl[sym]; 00075 sname->len = (uint16_t)len; 00076 if (lit || mrb_ro_data_p(name)) { 00077 sname->name = name; 00078 sname->lit = TRUE; 00079 } 00080 else { 00081 p = (char *)mrb_malloc(mrb, len+1); 00082 memcpy(p, name, len); 00083 p[len] = 0; 00084 sname->name = (const char*)p; 00085 sname->lit = FALSE; 00086 } 00087 kh_put(n2s, mrb, h, sym); 00088 00089 return sym; 00090 } 00091 00092 MRB_API mrb_sym 00093 mrb_intern(mrb_state *mrb, const char *name, size_t len) 00094 { 00095 return sym_intern(mrb, name, len, FALSE); 00096 } 00097 00098 MRB_API mrb_sym 00099 mrb_intern_static(mrb_state *mrb, const char *name, size_t len) 00100 { 00101 return sym_intern(mrb, name, len, TRUE); 00102 } 00103 00104 MRB_API mrb_sym 00105 mrb_intern_cstr(mrb_state *mrb, const char *name) 00106 { 00107 return mrb_intern(mrb, name, strlen(name)); 00108 } 00109 00110 MRB_API mrb_sym 00111 mrb_intern_str(mrb_state *mrb, mrb_value str) 00112 { 00113 return mrb_intern(mrb, RSTRING_PTR(str), RSTRING_LEN(str)); 00114 } 00115 00116 MRB_API mrb_value 00117 mrb_check_intern(mrb_state *mrb, const char *name, size_t len) 00118 { 00119 khash_t(n2s) *h = mrb->name2sym; 00120 symbol_name *sname = mrb->symtbl; 00121 khiter_t k; 00122 00123 sym_validate_len(mrb, len); 00124 sname->len = (uint16_t)len; 00125 sname->name = name; 00126 00127 k = kh_get(n2s, mrb, h, 0); 00128 if (k != kh_end(h)) { 00129 return mrb_symbol_value(kh_key(h, k)); 00130 } 00131 return mrb_nil_value(); 00132 } 00133 00134 MRB_API mrb_value 00135 mrb_check_intern_cstr(mrb_state *mrb, const char *name) 00136 { 00137 return mrb_check_intern(mrb, name, (mrb_int)strlen(name)); 00138 } 00139 00140 MRB_API mrb_value 00141 mrb_check_intern_str(mrb_state *mrb, mrb_value str) 00142 { 00143 return mrb_check_intern(mrb, RSTRING_PTR(str), RSTRING_LEN(str)); 00144 } 00145 00146 /* lenp must be a pointer to a size_t variable */ 00147 MRB_API const char* 00148 mrb_sym2name_len(mrb_state *mrb, mrb_sym sym, mrb_int *lenp) 00149 { 00150 if (sym == 0 || mrb->symidx < sym) { 00151 if (lenp) *lenp = 0; 00152 return NULL; 00153 } 00154 00155 if (lenp) *lenp = mrb->symtbl[sym].len; 00156 return mrb->symtbl[sym].name; 00157 } 00158 00159 void 00160 mrb_free_symtbl(mrb_state *mrb) 00161 { 00162 mrb_sym i, lim; 00163 00164 for (i=1, lim=mrb->symidx+1; i<lim; i++) { 00165 if (!mrb->symtbl[i].lit) { 00166 mrb_free(mrb, (char*)mrb->symtbl[i].name); 00167 } 00168 } 00169 mrb_free(mrb, mrb->symtbl); 00170 kh_destroy(n2s, mrb, mrb->name2sym); 00171 } 00172 00173 void 00174 mrb_init_symtbl(mrb_state *mrb) 00175 { 00176 mrb->name2sym = kh_init(n2s, mrb); 00177 } 00178 00179 /********************************************************************** 00180 * Document-class: Symbol 00181 * 00182 * <code>Symbol</code> objects represent names and some strings 00183 * inside the Ruby 00184 * interpreter. They are generated using the <code>:name</code> and 00185 * <code>:"string"</code> literals 00186 * syntax, and by the various <code>to_sym</code> methods. The same 00187 * <code>Symbol</code> object will be created for a given name or string 00188 * for the duration of a program's execution, regardless of the context 00189 * or meaning of that name. Thus if <code>Fred</code> is a constant in 00190 * one context, a method in another, and a class in a third, the 00191 * <code>Symbol</code> <code>:Fred</code> will be the same object in 00192 * all three contexts. 00193 * 00194 * module One 00195 * class Fred 00196 * end 00197 * $f1 = :Fred 00198 * end 00199 * module Two 00200 * Fred = 1 00201 * $f2 = :Fred 00202 * end 00203 * def Fred() 00204 * end 00205 * $f3 = :Fred 00206 * $f1.object_id #=> 2514190 00207 * $f2.object_id #=> 2514190 00208 * $f3.object_id #=> 2514190 00209 * 00210 */ 00211 00212 00213 /* 15.2.11.3.1 */ 00214 /* 00215 * call-seq: 00216 * sym == obj -> true or false 00217 * 00218 * Equality---If <i>sym</i> and <i>obj</i> are exactly the same 00219 * symbol, returns <code>true</code>. 00220 */ 00221 00222 static mrb_value 00223 sym_equal(mrb_state *mrb, mrb_value sym1) 00224 { 00225 mrb_value sym2; 00226 00227 mrb_get_args(mrb, "o", &sym2); 00228 00229 return mrb_bool_value(mrb_obj_equal(mrb, sym1, sym2)); 00230 } 00231 00232 /* 15.2.11.3.2 */ 00233 /* 15.2.11.3.3 */ 00234 /* 00235 * call-seq: 00236 * sym.id2name -> string 00237 * sym.to_s -> string 00238 * 00239 * Returns the name or string corresponding to <i>sym</i>. 00240 * 00241 * :fred.id2name #=> "fred" 00242 */ 00243 static mrb_value 00244 mrb_sym_to_s(mrb_state *mrb, mrb_value sym) 00245 { 00246 mrb_sym id = mrb_symbol(sym); 00247 const char *p; 00248 mrb_int len; 00249 00250 p = mrb_sym2name_len(mrb, id, &len); 00251 return mrb_str_new_static(mrb, p, len); 00252 } 00253 00254 /* 15.2.11.3.4 */ 00255 /* 00256 * call-seq: 00257 * sym.to_sym -> sym 00258 * sym.intern -> sym 00259 * 00260 * In general, <code>to_sym</code> returns the <code>Symbol</code> corresponding 00261 * to an object. As <i>sym</i> is already a symbol, <code>self</code> is returned 00262 * in this case. 00263 */ 00264 00265 static mrb_value 00266 sym_to_sym(mrb_state *mrb, mrb_value sym) 00267 { 00268 return sym; 00269 } 00270 00271 /* 15.2.11.3.5(x) */ 00272 /* 00273 * call-seq: 00274 * sym.inspect -> string 00275 * 00276 * Returns the representation of <i>sym</i> as a symbol literal. 00277 * 00278 * :fred.inspect #=> ":fred" 00279 */ 00280 00281 #if __STDC__ 00282 # define SIGN_EXTEND_CHAR(c) ((signed char)(c)) 00283 #else /* not __STDC__ */ 00284 /* As in Harbison and Steele. */ 00285 # define SIGN_EXTEND_CHAR(c) ((((unsigned char)(c)) ^ 128) - 128) 00286 #endif 00287 #define is_identchar(c) (SIGN_EXTEND_CHAR(c)!=-1&&(ISALNUM(c) || (c) == '_')) 00288 00289 static mrb_bool 00290 is_special_global_name(const char* m) 00291 { 00292 switch (*m) { 00293 case '~': case '*': case '$': case '?': case '!': case '@': 00294 case '/': case '\\': case ';': case ',': case '.': case '=': 00295 case ':': case '<': case '>': case '\"': 00296 case '&': case '`': case '\'': case '+': 00297 case '0': 00298 ++m; 00299 break; 00300 case '-': 00301 ++m; 00302 if (is_identchar(*m)) m += 1; 00303 break; 00304 default: 00305 if (!ISDIGIT(*m)) return FALSE; 00306 do ++m; while (ISDIGIT(*m)); 00307 break; 00308 } 00309 return !*m; 00310 } 00311 00312 static mrb_bool 00313 symname_p(const char *name) 00314 { 00315 const char *m = name; 00316 mrb_bool localid = FALSE; 00317 00318 if (!m) return FALSE; 00319 switch (*m) { 00320 case '\0': 00321 return FALSE; 00322 00323 case '$': 00324 if (is_special_global_name(++m)) return TRUE; 00325 goto id; 00326 00327 case '@': 00328 if (*++m == '@') ++m; 00329 goto id; 00330 00331 case '<': 00332 switch (*++m) { 00333 case '<': ++m; break; 00334 case '=': if (*++m == '>') ++m; break; 00335 default: break; 00336 } 00337 break; 00338 00339 case '>': 00340 switch (*++m) { 00341 case '>': case '=': ++m; break; 00342 default: break; 00343 } 00344 break; 00345 00346 case '=': 00347 switch (*++m) { 00348 case '~': ++m; break; 00349 case '=': if (*++m == '=') ++m; break; 00350 default: return FALSE; 00351 } 00352 break; 00353 00354 case '*': 00355 if (*++m == '*') ++m; 00356 break; 00357 case '!': 00358 if (*++m == '=') ++m; 00359 break; 00360 case '+': case '-': 00361 if (*++m == '@') ++m; 00362 break; 00363 case '|': 00364 if (*++m == '|') ++m; 00365 break; 00366 case '&': 00367 if (*++m == '&') ++m; 00368 break; 00369 00370 case '^': case '/': case '%': case '~': case '`': 00371 ++m; 00372 break; 00373 00374 case '[': 00375 if (*++m != ']') return FALSE; 00376 if (*++m == '=') ++m; 00377 break; 00378 00379 default: 00380 localid = !ISUPPER(*m); 00381 id: 00382 if (*m != '_' && !ISALPHA(*m)) return FALSE; 00383 while (is_identchar(*m)) m += 1; 00384 if (localid) { 00385 switch (*m) { 00386 case '!': case '?': case '=': ++m; 00387 default: break; 00388 } 00389 } 00390 break; 00391 } 00392 return *m ? FALSE : TRUE; 00393 } 00394 00395 static mrb_value 00396 sym_inspect(mrb_state *mrb, mrb_value sym) 00397 { 00398 mrb_value str; 00399 const char *name; 00400 mrb_int len; 00401 mrb_sym id = mrb_symbol(sym); 00402 char *sp; 00403 00404 name = mrb_sym2name_len(mrb, id, &len); 00405 str = mrb_str_new(mrb, 0, len+1); 00406 sp = RSTRING_PTR(str); 00407 RSTRING_PTR(str)[0] = ':'; 00408 memcpy(sp+1, name, len); 00409 mrb_assert_int_fit(mrb_int, len, size_t, SIZE_MAX); 00410 if (!symname_p(name) || strlen(name) != (size_t)len) { 00411 str = mrb_str_dump(mrb, str); 00412 sp = RSTRING_PTR(str); 00413 sp[0] = ':'; 00414 sp[1] = '"'; 00415 } 00416 return str; 00417 } 00418 00419 MRB_API mrb_value 00420 mrb_sym2str(mrb_state *mrb, mrb_sym sym) 00421 { 00422 mrb_int len; 00423 const char *name = mrb_sym2name_len(mrb, sym, &len); 00424 00425 if (!name) return mrb_undef_value(); /* can't happen */ 00426 return mrb_str_new_static(mrb, name, len); 00427 } 00428 00429 MRB_API const char* 00430 mrb_sym2name(mrb_state *mrb, mrb_sym sym) 00431 { 00432 mrb_int len; 00433 const char *name = mrb_sym2name_len(mrb, sym, &len); 00434 00435 if (!name) return NULL; 00436 if (symname_p(name) && strlen(name) == (size_t)len) { 00437 return name; 00438 } 00439 else { 00440 mrb_value str = mrb_str_dump(mrb, mrb_str_new_static(mrb, name, len)); 00441 return RSTRING_PTR(str); 00442 } 00443 } 00444 00445 #define lesser(a,b) (((a)>(b))?(b):(a)) 00446 00447 static mrb_value 00448 sym_cmp(mrb_state *mrb, mrb_value s1) 00449 { 00450 mrb_value s2; 00451 mrb_sym sym1, sym2; 00452 00453 mrb_get_args(mrb, "o", &s2); 00454 if (mrb_type(s2) != MRB_TT_SYMBOL) return mrb_nil_value(); 00455 sym1 = mrb_symbol(s1); 00456 sym2 = mrb_symbol(s2); 00457 if (sym1 == sym2) return mrb_fixnum_value(0); 00458 else { 00459 const char *p1, *p2; 00460 int retval; 00461 mrb_int len, len1, len2; 00462 00463 p1 = mrb_sym2name_len(mrb, sym1, &len1); 00464 p2 = mrb_sym2name_len(mrb, sym2, &len2); 00465 len = lesser(len1, len2); 00466 retval = memcmp(p1, p2, len); 00467 if (retval == 0) { 00468 if (len1 == len2) return mrb_fixnum_value(0); 00469 if (len1 > len2) return mrb_fixnum_value(1); 00470 return mrb_fixnum_value(-1); 00471 } 00472 if (retval > 0) return mrb_fixnum_value(1); 00473 return mrb_fixnum_value(-1); 00474 } 00475 } 00476 00477 void 00478 mrb_init_symbol(mrb_state *mrb) 00479 { 00480 struct RClass *sym; 00481 00482 sym = mrb->symbol_class = mrb_define_class(mrb, "Symbol", mrb->object_class); /* 15.2.11 */ 00483 00484 mrb_define_method(mrb, sym, "===", sym_equal, MRB_ARGS_REQ(1)); /* 15.2.11.3.1 */ 00485 mrb_define_method(mrb, sym, "id2name", mrb_sym_to_s, MRB_ARGS_NONE()); /* 15.2.11.3.2 */ 00486 mrb_define_method(mrb, sym, "to_s", mrb_sym_to_s, MRB_ARGS_NONE()); /* 15.2.11.3.3 */ 00487 mrb_define_method(mrb, sym, "to_sym", sym_to_sym, MRB_ARGS_NONE()); /* 15.2.11.3.4 */ 00488 mrb_define_method(mrb, sym, "inspect", sym_inspect, MRB_ARGS_NONE()); /* 15.2.11.3.5(x) */ 00489 mrb_define_method(mrb, sym, "<=>", sym_cmp, MRB_ARGS_REQ(1)); 00490 } 00491
Generated on Tue Jul 12 2022 18:00:35 by 1.7.2