mbed I/F binding for mruby
Dependents: mruby_mbed_web mirb_mbed
variable.c
00001 /* 00002 ** variable.c - mruby variables 00003 ** 00004 ** See Copyright Notice in mruby.h 00005 */ 00006 00007 #include <ctype.h> 00008 #include "mruby.h" 00009 #include "mruby/array.h" 00010 #include "mruby/class.h" 00011 #include "mruby/proc.h" 00012 #include "mruby/string.h" 00013 00014 typedef int (iv_foreach_func)(mrb_state*,mrb_sym,mrb_value,void*); 00015 00016 #ifdef MRB_USE_IV_SEGLIST 00017 00018 #ifndef MRB_SEGMENT_SIZE 00019 #define MRB_SEGMENT_SIZE 4 00020 #endif 00021 00022 typedef struct segment { 00023 mrb_sym key[MRB_SEGMENT_SIZE]; 00024 mrb_value val[MRB_SEGMENT_SIZE]; 00025 struct segment *next; 00026 } segment; 00027 00028 /* Instance variable table structure */ 00029 typedef struct iv_tbl { 00030 segment *rootseg; 00031 size_t size; 00032 size_t last_len; 00033 } iv_tbl; 00034 00035 /* 00036 * Creates the instance variable table. 00037 * 00038 * Parameters 00039 * mrb 00040 * Returns 00041 * the instance variable table. 00042 */ 00043 static iv_tbl* 00044 iv_new(mrb_state *mrb) 00045 { 00046 iv_tbl *t; 00047 00048 t = mrb_malloc(mrb, sizeof(iv_tbl)); 00049 t->size = 0; 00050 t->rootseg = NULL; 00051 t->last_len = 0; 00052 00053 return t; 00054 } 00055 00056 /* 00057 * Set the value for the symbol in the instance variable table. 00058 * 00059 * Parameters 00060 * mrb 00061 * t the instance variable table to be set in. 00062 * sym the symbol to be used as the key. 00063 * val the value to be set. 00064 */ 00065 static void 00066 iv_put(mrb_state *mrb, iv_tbl *t, mrb_sym sym, mrb_value val) 00067 { 00068 segment *seg = t->rootseg; 00069 segment *prev = NULL; 00070 segment *matched_seg = NULL; 00071 size_t matched_idx = 0; 00072 size_t i; 00073 00074 while (seg) { 00075 for (i=0; i<MRB_SEGMENT_SIZE; i++) { 00076 mrb_sym key = seg->key[i]; 00077 /* Found room in last segment after last_len */ 00078 if (!seg->next && i >= t->last_len) { 00079 seg->key[i] = sym; 00080 seg->val[i] = val; 00081 t->last_len = i+1; 00082 t->size++; 00083 return; 00084 } 00085 if (!matched_seg && key == 0) { 00086 matched_seg = seg; 00087 matched_idx = i; 00088 } 00089 else if (key == sym) { 00090 seg->val[i] = val; 00091 return; 00092 } 00093 } 00094 prev = seg; 00095 seg = seg->next; 00096 } 00097 00098 /* Not found */ 00099 t->size++; 00100 if (matched_seg) { 00101 matched_seg->key[matched_idx] = sym; 00102 matched_seg->val[matched_idx] = val; 00103 return; 00104 } 00105 00106 seg = mrb_malloc(mrb, sizeof(segment)); 00107 if (!seg) return; 00108 seg->next = NULL; 00109 seg->key[0] = sym; 00110 seg->val[0] = val; 00111 t->last_len = 1; 00112 if (prev) { 00113 prev->next = seg; 00114 } 00115 else { 00116 t->rootseg = seg; 00117 } 00118 } 00119 00120 /* 00121 * Get a value for a symbol from the instance variable table. 00122 * 00123 * Parameters 00124 * mrb 00125 * t the variable table to be searched. 00126 * sym the symbol to be used as the key. 00127 * vp the value pointer. Receives the value if the specified symbol is 00128 * contained in the instance variable table. 00129 * Returns 00130 * true if the specified symbol is contained in the instance variable table. 00131 */ 00132 static mrb_bool 00133 iv_get(mrb_state *mrb, iv_tbl *t, mrb_sym sym, mrb_value *vp) 00134 { 00135 segment *seg; 00136 size_t i; 00137 00138 seg = t->rootseg; 00139 while (seg) { 00140 for (i=0; i<MRB_SEGMENT_SIZE; i++) { 00141 mrb_sym key = seg->key[i]; 00142 00143 if (!seg->next && i >= t->last_len) { 00144 return FALSE; 00145 } 00146 if (key == sym) { 00147 if (vp) *vp = seg->val[i]; 00148 return TRUE; 00149 } 00150 } 00151 seg = seg->next; 00152 } 00153 return FALSE; 00154 } 00155 00156 /* 00157 * Deletes the value for the symbol from the instance variable table. 00158 * 00159 * Parameters 00160 * t the variable table to be searched. 00161 * sym the symbol to be used as the key. 00162 * vp the value pointer. Receive the deleted value if the symbol is 00163 * contained in the instance variable table. 00164 * Returns 00165 * true if the specified symbol is contained in the instance variable table. 00166 */ 00167 static mrb_bool 00168 iv_del(mrb_state *mrb, iv_tbl *t, mrb_sym sym, mrb_value *vp) 00169 { 00170 segment *seg; 00171 size_t i; 00172 00173 seg = t->rootseg; 00174 while (seg) { 00175 for (i=0; i<MRB_SEGMENT_SIZE; i++) { 00176 mrb_sym key = seg->key[i]; 00177 00178 if (!seg->next && i >= t->last_len) { 00179 return FALSE; 00180 } 00181 if (key == sym) { 00182 t->size--; 00183 seg->key[i] = 0; 00184 if (vp) *vp = seg->val[i]; 00185 return TRUE; 00186 } 00187 } 00188 seg = seg->next; 00189 } 00190 return FALSE; 00191 } 00192 00193 static mrb_bool 00194 iv_foreach(mrb_state *mrb, iv_tbl *t, iv_foreach_func *func, void *p) 00195 { 00196 segment *seg; 00197 size_t i; 00198 int n; 00199 00200 seg = t->rootseg; 00201 while (seg) { 00202 for (i=0; i<MRB_SEGMENT_SIZE; i++) { 00203 mrb_sym key = seg->key[i]; 00204 00205 /* no value in last segment after last_len */ 00206 if (!seg->next && i >= t->last_len) { 00207 return FALSE; 00208 } 00209 if (key != 0) { 00210 n =(*func)(mrb, key, seg->val[i], p); 00211 if (n > 0) return FALSE; 00212 if (n < 0) { 00213 t->size--; 00214 seg->key[i] = 0; 00215 } 00216 } 00217 } 00218 seg = seg->next; 00219 } 00220 return TRUE; 00221 } 00222 00223 static size_t 00224 iv_size(mrb_state *mrb, iv_tbl *t) 00225 { 00226 segment *seg; 00227 size_t size = 0; 00228 00229 if (!t) return 0; 00230 if (t->size > 0) return t->size; 00231 seg = t->rootseg; 00232 while (seg) { 00233 if (seg->next == NULL) { 00234 size += t->last_len; 00235 return size; 00236 } 00237 seg = seg->next; 00238 size += MRB_SEGMENT_SIZE; 00239 } 00240 /* empty iv_tbl */ 00241 return 0; 00242 } 00243 00244 static iv_tbl* 00245 iv_copy(mrb_state *mrb, iv_tbl *t) 00246 { 00247 segment *seg; 00248 iv_tbl *t2; 00249 00250 size_t i; 00251 00252 seg = t->rootseg; 00253 t2 = iv_new(mrb); 00254 00255 while (seg != NULL) { 00256 for (i=0; i<MRB_SEGMENT_SIZE; i++) { 00257 mrb_sym key = seg->key[i]; 00258 mrb_value val = seg->val[i]; 00259 00260 if ((seg->next == NULL) && (i >= t->last_len)) { 00261 return t2; 00262 } 00263 iv_put(mrb, t2, key, val); 00264 } 00265 seg = seg->next; 00266 } 00267 return t2; 00268 } 00269 00270 static void 00271 iv_free(mrb_state *mrb, iv_tbl *t) 00272 { 00273 segment *seg; 00274 00275 seg = t->rootseg; 00276 while (seg) { 00277 segment *p = seg; 00278 seg = seg->next; 00279 mrb_free(mrb, p); 00280 } 00281 mrb_free(mrb, t); 00282 } 00283 00284 #else 00285 00286 #include "mruby/khash.h" 00287 00288 #ifndef MRB_IVHASH_INIT_SIZE 00289 #define MRB_IVHASH_INIT_SIZE 8 00290 #endif 00291 00292 KHASH_DECLARE(iv, mrb_sym, mrb_value, TRUE) 00293 KHASH_DEFINE(iv, mrb_sym, mrb_value, TRUE, kh_int_hash_func, kh_int_hash_equal) 00294 00295 typedef struct iv_tbl { 00296 khash_t(iv) h; 00297 } iv_tbl; 00298 00299 static iv_tbl* 00300 iv_new(mrb_state *mrb) 00301 { 00302 return (iv_tbl*)kh_init_size(iv, mrb, MRB_IVHASH_INIT_SIZE); 00303 } 00304 00305 static void 00306 iv_put(mrb_state *mrb, iv_tbl *t, mrb_sym sym, mrb_value val) 00307 { 00308 khash_t(iv) *h = &t->h; 00309 khiter_t k; 00310 00311 k = kh_put(iv, mrb, h, sym); 00312 kh_value(h, k) = val; 00313 } 00314 00315 static mrb_bool 00316 iv_get(mrb_state *mrb, iv_tbl *t, mrb_sym sym, mrb_value *vp) 00317 { 00318 khash_t(iv) *h = &t->h; 00319 khiter_t k; 00320 00321 k = kh_get(iv, mrb, h, sym); 00322 if (k != kh_end(h)) { 00323 if (vp) *vp = kh_value(h, k); 00324 return TRUE; 00325 } 00326 return FALSE; 00327 } 00328 00329 static mrb_bool 00330 iv_del(mrb_state *mrb, iv_tbl *t, mrb_sym sym, mrb_value *vp) 00331 { 00332 khash_t(iv) *h = &t->h; 00333 khiter_t k; 00334 00335 if (h) { 00336 k = kh_get(iv, mrb, h, sym); 00337 if (k != kh_end(h)) { 00338 mrb_value val = kh_value(h, k); 00339 kh_del(iv, mrb, h, k); 00340 if (vp) *vp = val; 00341 return TRUE; 00342 } 00343 } 00344 return FALSE; 00345 } 00346 00347 static mrb_bool 00348 iv_foreach(mrb_state *mrb, iv_tbl *t, iv_foreach_func *func, void *p) 00349 { 00350 khash_t(iv) *h = &t->h; 00351 khiter_t k; 00352 int n; 00353 00354 if (h) { 00355 for (k = kh_begin(h); k != kh_end(h); k++) { 00356 if (kh_exist(h, k)) { 00357 n = (*func)(mrb, kh_key(h, k), kh_value(h, k), p); 00358 if (n > 0) return FALSE; 00359 if (n < 0) { 00360 kh_del(iv, mrb, h, k); 00361 } 00362 } 00363 } 00364 } 00365 return TRUE; 00366 } 00367 00368 static size_t 00369 iv_size(mrb_state *mrb, iv_tbl *t) 00370 { 00371 khash_t(iv) *h; 00372 00373 if (t && (h = &t->h)) { 00374 return kh_size(h); 00375 } 00376 return 0; 00377 } 00378 00379 static iv_tbl* 00380 iv_copy(mrb_state *mrb, iv_tbl *t) 00381 { 00382 return (iv_tbl*)kh_copy(iv, mrb, &t->h); 00383 } 00384 00385 static void 00386 iv_free(mrb_state *mrb, iv_tbl *t) 00387 { 00388 kh_destroy(iv, mrb, &t->h); 00389 } 00390 00391 #endif 00392 00393 static int 00394 iv_mark_i(mrb_state *mrb, mrb_sym sym, mrb_value v, void *p) 00395 { 00396 mrb_gc_mark_value(mrb, v); 00397 return 0; 00398 } 00399 00400 static void 00401 mark_tbl(mrb_state *mrb, iv_tbl *t) 00402 { 00403 if (t) { 00404 iv_foreach(mrb, t, iv_mark_i, 0); 00405 } 00406 } 00407 00408 void 00409 mrb_gc_mark_gv(mrb_state *mrb) 00410 { 00411 mark_tbl(mrb, mrb->globals); 00412 } 00413 00414 void 00415 mrb_gc_free_gv(mrb_state *mrb) 00416 { 00417 if (mrb->globals) 00418 iv_free(mrb, mrb->globals); 00419 } 00420 00421 void 00422 mrb_gc_mark_iv(mrb_state *mrb, struct RObject *obj) 00423 { 00424 mark_tbl(mrb, obj->iv); 00425 } 00426 00427 size_t 00428 mrb_gc_mark_iv_size(mrb_state *mrb, struct RObject *obj) 00429 { 00430 return iv_size(mrb, obj->iv); 00431 } 00432 00433 void 00434 mrb_gc_free_iv(mrb_state *mrb, struct RObject *obj) 00435 { 00436 if (obj->iv) { 00437 iv_free(mrb, obj->iv); 00438 } 00439 } 00440 00441 mrb_value 00442 mrb_vm_special_get(mrb_state *mrb, mrb_sym i) 00443 { 00444 return mrb_fixnum_value(0); 00445 } 00446 00447 void 00448 mrb_vm_special_set(mrb_state *mrb, mrb_sym i, mrb_value v) 00449 { 00450 } 00451 00452 static mrb_bool 00453 obj_iv_p(mrb_value obj) 00454 { 00455 switch (mrb_type(obj)) { 00456 case MRB_TT_OBJECT: 00457 case MRB_TT_CLASS: 00458 case MRB_TT_MODULE: 00459 case MRB_TT_SCLASS: 00460 case MRB_TT_HASH: 00461 case MRB_TT_DATA: 00462 case MRB_TT_EXCEPTION: 00463 return TRUE; 00464 default: 00465 return FALSE; 00466 } 00467 } 00468 00469 MRB_API mrb_value 00470 mrb_obj_iv_get(mrb_state *mrb, struct RObject *obj, mrb_sym sym) 00471 { 00472 mrb_value v; 00473 00474 if (obj->iv && iv_get(mrb, obj->iv, sym, &v)) 00475 return v; 00476 return mrb_nil_value(); 00477 } 00478 00479 MRB_API mrb_value 00480 mrb_iv_get(mrb_state *mrb, mrb_value obj, mrb_sym sym) 00481 { 00482 if (obj_iv_p(obj)) { 00483 return mrb_obj_iv_get(mrb, mrb_obj_ptr(obj), sym); 00484 } 00485 return mrb_nil_value(); 00486 } 00487 00488 MRB_API void 00489 mrb_obj_iv_set(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v) 00490 { 00491 iv_tbl *t = obj->iv; 00492 00493 if (!t) { 00494 t = obj->iv = iv_new(mrb); 00495 } 00496 mrb_write_barrier(mrb, (struct RBasic*)obj); 00497 iv_put(mrb, t, sym, v); 00498 } 00499 00500 MRB_API void 00501 mrb_obj_iv_ifnone(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v) 00502 { 00503 iv_tbl *t = obj->iv; 00504 00505 if (!t) { 00506 t = obj->iv = iv_new(mrb); 00507 } 00508 else if (iv_get(mrb, t, sym, &v)) { 00509 return; 00510 } 00511 mrb_write_barrier(mrb, (struct RBasic*)obj); 00512 iv_put(mrb, t, sym, v); 00513 } 00514 00515 MRB_API void 00516 mrb_iv_set(mrb_state *mrb, mrb_value obj, mrb_sym sym, mrb_value v) 00517 { 00518 if (obj_iv_p(obj)) { 00519 mrb_obj_iv_set(mrb, mrb_obj_ptr(obj), sym, v); 00520 } 00521 else { 00522 mrb_raise(mrb, E_ARGUMENT_ERROR, "cannot set instance variable"); 00523 } 00524 } 00525 00526 MRB_API mrb_bool 00527 mrb_obj_iv_defined(mrb_state *mrb, struct RObject *obj, mrb_sym sym) 00528 { 00529 iv_tbl *t; 00530 00531 t = obj->iv; 00532 if (t) { 00533 return iv_get(mrb, t, sym, NULL); 00534 } 00535 return FALSE; 00536 } 00537 00538 MRB_API mrb_bool 00539 mrb_iv_defined(mrb_state *mrb, mrb_value obj, mrb_sym sym) 00540 { 00541 if (!obj_iv_p(obj)) return FALSE; 00542 return mrb_obj_iv_defined(mrb, mrb_obj_ptr(obj), sym); 00543 } 00544 00545 #define identchar(c) (ISALNUM(c) || (c) == '_' || !ISASCII(c)) 00546 00547 MRB_API mrb_bool 00548 mrb_iv_p(mrb_state *mrb, mrb_sym iv_name) 00549 { 00550 const char *s; 00551 mrb_int i, len; 00552 00553 s = mrb_sym2name_len(mrb, iv_name, &len); 00554 if (len < 2) return FALSE; 00555 if (s[0] != '@') return FALSE; 00556 if (s[1] == '@') return FALSE; 00557 for (i=1; i<len; i++) { 00558 if (!identchar(s[i])) return FALSE; 00559 } 00560 return TRUE; 00561 } 00562 00563 MRB_API void 00564 mrb_iv_check(mrb_state *mrb, mrb_sym iv_name) 00565 { 00566 if (!mrb_iv_p(mrb, iv_name)) { 00567 mrb_name_error(mrb, iv_name, "`%S' is not allowed as an instance variable name", mrb_sym2str(mrb, iv_name)); 00568 } 00569 } 00570 00571 MRB_API void 00572 mrb_iv_copy(mrb_state *mrb, mrb_value dest, mrb_value src) 00573 { 00574 struct RObject *d = mrb_obj_ptr(dest); 00575 struct RObject *s = mrb_obj_ptr(src); 00576 00577 if (d->iv) { 00578 iv_free(mrb, d->iv); 00579 d->iv = 0; 00580 } 00581 if (s->iv) { 00582 mrb_write_barrier(mrb, (struct RBasic*)d); 00583 d->iv = iv_copy(mrb, s->iv); 00584 } 00585 } 00586 00587 static int 00588 inspect_i(mrb_state *mrb, mrb_sym sym, mrb_value v, void *p) 00589 { 00590 mrb_value str = *(mrb_value*)p; 00591 const char *s; 00592 mrb_int len; 00593 mrb_value ins; 00594 char *sp = RSTRING_PTR(str); 00595 00596 /* need not to show internal data */ 00597 if (sp[0] == '-') { /* first element */ 00598 sp[0] = '#'; 00599 mrb_str_cat_lit(mrb, str, " "); 00600 } 00601 else { 00602 mrb_str_cat_lit(mrb, str, ", "); 00603 } 00604 s = mrb_sym2name_len(mrb, sym, &len); 00605 mrb_str_cat(mrb, str, s, len); 00606 mrb_str_cat_lit(mrb, str, "="); 00607 if (mrb_type(v) == MRB_TT_OBJECT) { 00608 ins = mrb_any_to_s(mrb, v); 00609 } 00610 else { 00611 ins = mrb_inspect(mrb, v); 00612 } 00613 mrb_str_append(mrb, str, ins); 00614 return 0; 00615 } 00616 00617 mrb_value 00618 mrb_obj_iv_inspect(mrb_state *mrb, struct RObject *obj) 00619 { 00620 iv_tbl *t = obj->iv; 00621 size_t len = iv_size(mrb, t); 00622 00623 if (len > 0) { 00624 const char *cn = mrb_obj_classname(mrb, mrb_obj_value(obj)); 00625 mrb_value str = mrb_str_buf_new(mrb, 30); 00626 00627 mrb_str_cat_lit(mrb, str, "-<"); 00628 mrb_str_cat_cstr(mrb, str, cn); 00629 mrb_str_cat_lit(mrb, str, ":"); 00630 mrb_str_concat(mrb, str, mrb_ptr_to_str(mrb, obj)); 00631 00632 iv_foreach(mrb, t, inspect_i, &str); 00633 mrb_str_cat_lit(mrb, str, ">"); 00634 return str; 00635 } 00636 return mrb_any_to_s(mrb, mrb_obj_value(obj)); 00637 } 00638 00639 MRB_API mrb_value 00640 mrb_iv_remove(mrb_state *mrb, mrb_value obj, mrb_sym sym) 00641 { 00642 if (obj_iv_p(obj)) { 00643 iv_tbl *t = mrb_obj_ptr(obj)->iv; 00644 mrb_value val; 00645 00646 if (t && iv_del(mrb, t, sym, &val)) { 00647 return val; 00648 } 00649 } 00650 return mrb_undef_value(); 00651 } 00652 00653 mrb_value 00654 mrb_vm_iv_get(mrb_state *mrb, mrb_sym sym) 00655 { 00656 /* get self */ 00657 return mrb_iv_get(mrb, mrb->c->stack[0], sym); 00658 } 00659 00660 void 00661 mrb_vm_iv_set(mrb_state *mrb, mrb_sym sym, mrb_value v) 00662 { 00663 /* get self */ 00664 mrb_iv_set(mrb, mrb->c->stack[0], sym, v); 00665 } 00666 00667 static int 00668 iv_i(mrb_state *mrb, mrb_sym sym, mrb_value v, void *p) 00669 { 00670 mrb_value ary; 00671 const char* s; 00672 mrb_int len; 00673 00674 ary = *(mrb_value*)p; 00675 s = mrb_sym2name_len(mrb, sym, &len); 00676 if (len > 1 && s[0] == '@' && s[1] != '@') { 00677 mrb_ary_push(mrb, ary, mrb_symbol_value(sym)); 00678 } 00679 return 0; 00680 } 00681 00682 /* 15.3.1.3.23 */ 00683 /* 00684 * call-seq: 00685 * obj.instance_variables -> array 00686 * 00687 * Returns an array of instance variable names for the receiver. Note 00688 * that simply defining an accessor does not create the corresponding 00689 * instance variable. 00690 * 00691 * class Fred 00692 * attr_accessor :a1 00693 * def initialize 00694 * @iv = 3 00695 * end 00696 * end 00697 * Fred.new.instance_variables #=> [:@iv] 00698 */ 00699 mrb_value 00700 mrb_obj_instance_variables(mrb_state *mrb, mrb_value self) 00701 { 00702 mrb_value ary; 00703 00704 ary = mrb_ary_new(mrb); 00705 if (obj_iv_p(self) && mrb_obj_ptr(self)->iv) { 00706 iv_foreach(mrb, mrb_obj_ptr(self)->iv, iv_i, &ary); 00707 } 00708 return ary; 00709 } 00710 00711 static int 00712 cv_i(mrb_state *mrb, mrb_sym sym, mrb_value v, void *p) 00713 { 00714 mrb_value ary; 00715 const char* s; 00716 mrb_int len; 00717 00718 ary = *(mrb_value*)p; 00719 s = mrb_sym2name_len(mrb, sym, &len); 00720 if (len > 2 && s[0] == '@' && s[1] == '@') { 00721 mrb_ary_push(mrb, ary, mrb_symbol_value(sym)); 00722 } 00723 return 0; 00724 } 00725 00726 /* 15.2.2.4.19 */ 00727 /* 00728 * call-seq: 00729 * mod.class_variables -> array 00730 * 00731 * Returns an array of the names of class variables in <i>mod</i>. 00732 * 00733 * class One 00734 * @@var1 = 1 00735 * end 00736 * class Two < One 00737 * @@var2 = 2 00738 * end 00739 * One.class_variables #=> [:@@var1] 00740 * Two.class_variables #=> [:@@var2] 00741 */ 00742 mrb_value 00743 mrb_mod_class_variables(mrb_state *mrb, mrb_value mod) 00744 { 00745 mrb_value ary; 00746 struct RClass *c; 00747 00748 ary = mrb_ary_new(mrb); 00749 c = mrb_class_ptr(mod); 00750 while (c) { 00751 if (c->iv) { 00752 iv_foreach(mrb, c->iv, cv_i, &ary); 00753 } 00754 c = c->super; 00755 } 00756 return ary; 00757 } 00758 00759 MRB_API mrb_value 00760 mrb_mod_cv_get(mrb_state *mrb, struct RClass * c, mrb_sym sym) 00761 { 00762 struct RClass * cls = c; 00763 00764 while (c) { 00765 if (c->iv) { 00766 iv_tbl *t = c->iv; 00767 mrb_value v; 00768 00769 if (iv_get(mrb, t, sym, &v)) 00770 return v; 00771 } 00772 c = c->super; 00773 } 00774 mrb_name_error(mrb, sym, "uninitialized class variable %S in %S", 00775 mrb_sym2str(mrb, sym), mrb_obj_value(cls)); 00776 /* not reached */ 00777 return mrb_nil_value(); 00778 } 00779 00780 MRB_API mrb_value 00781 mrb_cv_get(mrb_state *mrb, mrb_value mod, mrb_sym sym) 00782 { 00783 return mrb_mod_cv_get(mrb, mrb_class_ptr(mod), sym); 00784 } 00785 00786 MRB_API void 00787 mrb_mod_cv_set(mrb_state *mrb, struct RClass *c, mrb_sym sym, mrb_value v) 00788 { 00789 struct RClass * cls = c; 00790 00791 while (c) { 00792 if (c->iv) { 00793 iv_tbl *t = c->iv; 00794 00795 if (iv_get(mrb, t, sym, NULL)) { 00796 mrb_write_barrier(mrb, (struct RBasic*)c); 00797 iv_put(mrb, t, sym, v); 00798 return; 00799 } 00800 } 00801 c = c->super; 00802 } 00803 00804 if (!cls->iv) { 00805 cls->iv = iv_new(mrb); 00806 } 00807 00808 mrb_write_barrier(mrb, (struct RBasic*)cls); 00809 iv_put(mrb, cls->iv, sym, v); 00810 } 00811 00812 MRB_API void 00813 mrb_cv_set(mrb_state *mrb, mrb_value mod, mrb_sym sym, mrb_value v) 00814 { 00815 mrb_mod_cv_set(mrb, mrb_class_ptr(mod), sym, v); 00816 } 00817 00818 MRB_API mrb_bool 00819 mrb_mod_cv_defined(mrb_state *mrb, struct RClass * c, mrb_sym sym) 00820 { 00821 while (c) { 00822 if (c->iv) { 00823 iv_tbl *t = c->iv; 00824 if (iv_get(mrb, t, sym, NULL)) return TRUE; 00825 } 00826 c = c->super; 00827 } 00828 00829 return FALSE; 00830 } 00831 00832 MRB_API mrb_bool 00833 mrb_cv_defined(mrb_state *mrb, mrb_value mod, mrb_sym sym) 00834 { 00835 return mrb_mod_cv_defined(mrb, mrb_class_ptr(mod), sym); 00836 } 00837 00838 mrb_value 00839 mrb_vm_cv_get(mrb_state *mrb, mrb_sym sym) 00840 { 00841 struct RClass *c = mrb->c->ci->proc->target_class; 00842 00843 if (!c) c = mrb->c->ci->target_class; 00844 00845 return mrb_mod_cv_get(mrb, c, sym); 00846 } 00847 00848 void 00849 mrb_vm_cv_set(mrb_state *mrb, mrb_sym sym, mrb_value v) 00850 { 00851 struct RClass *c = mrb->c->ci->proc->target_class; 00852 00853 if (!c) c = mrb->c->ci->target_class; 00854 mrb_mod_cv_set(mrb, c, sym, v); 00855 } 00856 00857 static void 00858 mod_const_check(mrb_state *mrb, mrb_value mod) 00859 { 00860 switch (mrb_type(mod)) { 00861 case MRB_TT_CLASS: 00862 case MRB_TT_MODULE: 00863 case MRB_TT_SCLASS: 00864 break; 00865 default: 00866 mrb_raise(mrb, E_TYPE_ERROR, "constant look-up for non class/module"); 00867 break; 00868 } 00869 } 00870 00871 static mrb_value 00872 const_get(mrb_state *mrb, struct RClass *base, mrb_sym sym) 00873 { 00874 struct RClass *c = base; 00875 mrb_value v; 00876 iv_tbl *t; 00877 mrb_bool retry = FALSE; 00878 mrb_value name; 00879 00880 L_RETRY: 00881 while (c) { 00882 if (c->iv) { 00883 t = c->iv; 00884 if (iv_get(mrb, t, sym, &v)) 00885 return v; 00886 } 00887 c = c->super; 00888 } 00889 if (!retry && base && base->tt == MRB_TT_MODULE) { 00890 c = mrb->object_class; 00891 retry = TRUE; 00892 goto L_RETRY; 00893 } 00894 name = mrb_symbol_value(sym); 00895 return mrb_funcall_argv(mrb, mrb_obj_value(base), mrb_intern_lit(mrb, "const_missing"), 1, &name); 00896 } 00897 00898 MRB_API mrb_value 00899 mrb_const_get(mrb_state *mrb, mrb_value mod, mrb_sym sym) 00900 { 00901 mod_const_check(mrb, mod); 00902 return const_get(mrb, mrb_class_ptr(mod), sym); 00903 } 00904 00905 mrb_value 00906 mrb_vm_const_get(mrb_state *mrb, mrb_sym sym) 00907 { 00908 struct RClass *c = mrb->c->ci->proc->target_class; 00909 00910 if (!c) c = mrb->c->ci->target_class; 00911 if (c) { 00912 struct RClass *c2; 00913 mrb_value v; 00914 00915 if (c->iv && iv_get(mrb, c->iv, sym, &v)) { 00916 return v; 00917 } 00918 c2 = c; 00919 for (;;) { 00920 c2 = mrb_class_outer_module(mrb, c2); 00921 if (!c2) break; 00922 if (c2->iv && iv_get(mrb, c2->iv, sym, &v)) { 00923 return v; 00924 } 00925 } 00926 } 00927 return const_get(mrb, c, sym); 00928 } 00929 00930 MRB_API void 00931 mrb_const_set(mrb_state *mrb, mrb_value mod, mrb_sym sym, mrb_value v) 00932 { 00933 mod_const_check(mrb, mod); 00934 mrb_iv_set(mrb, mod, sym, v); 00935 } 00936 00937 void 00938 mrb_vm_const_set(mrb_state *mrb, mrb_sym sym, mrb_value v) 00939 { 00940 struct RClass *c = mrb->c->ci->proc->target_class; 00941 00942 if (!c) c = mrb->c->ci->target_class; 00943 mrb_obj_iv_set(mrb, (struct RObject*)c, sym, v); 00944 } 00945 00946 MRB_API void 00947 mrb_const_remove(mrb_state *mrb, mrb_value mod, mrb_sym sym) 00948 { 00949 mod_const_check(mrb, mod); 00950 mrb_iv_remove(mrb, mod, sym); 00951 } 00952 00953 MRB_API void 00954 mrb_define_const(mrb_state *mrb, struct RClass *mod, const char *name, mrb_value v) 00955 { 00956 mrb_obj_iv_set(mrb, (struct RObject*)mod, mrb_intern_cstr(mrb, name), v); 00957 } 00958 00959 MRB_API void 00960 mrb_define_global_const(mrb_state *mrb, const char *name, mrb_value val) 00961 { 00962 mrb_define_const(mrb, mrb->object_class, name, val); 00963 } 00964 00965 static int 00966 const_i(mrb_state *mrb, mrb_sym sym, mrb_value v, void *p) 00967 { 00968 mrb_value ary; 00969 const char* s; 00970 mrb_int len; 00971 00972 ary = *(mrb_value*)p; 00973 s = mrb_sym2name_len(mrb, sym, &len); 00974 if (len >= 1 && ISUPPER(s[0])) { 00975 mrb_ary_push(mrb, ary, mrb_symbol_value(sym)); 00976 } 00977 return 0; 00978 } 00979 00980 /* 15.2.2.4.24 */ 00981 /* 00982 * call-seq: 00983 * mod.constants -> array 00984 * 00985 * Returns an array of all names of contants defined in the receiver. 00986 */ 00987 mrb_value 00988 mrb_mod_constants(mrb_state *mrb, mrb_value mod) 00989 { 00990 mrb_value ary; 00991 mrb_bool inherit = TRUE; 00992 struct RClass *c = mrb_class_ptr(mod); 00993 00994 mrb_get_args(mrb, "|b", &inherit); 00995 ary = mrb_ary_new(mrb); 00996 while (c) { 00997 if (c->iv) { 00998 iv_foreach(mrb, c->iv, const_i, &ary); 00999 } 01000 if (!inherit) break; 01001 c = c->super; 01002 if (c == mrb->object_class) break; 01003 } 01004 return ary; 01005 } 01006 01007 MRB_API mrb_value 01008 mrb_gv_get(mrb_state *mrb, mrb_sym sym) 01009 { 01010 mrb_value v; 01011 01012 if (!mrb->globals) { 01013 return mrb_nil_value(); 01014 } 01015 if (iv_get(mrb, mrb->globals, sym, &v)) 01016 return v; 01017 return mrb_nil_value(); 01018 } 01019 01020 MRB_API void 01021 mrb_gv_set(mrb_state *mrb, mrb_sym sym, mrb_value v) 01022 { 01023 iv_tbl *t; 01024 01025 if (!mrb->globals) { 01026 t = mrb->globals = iv_new(mrb); 01027 } 01028 else { 01029 t = mrb->globals; 01030 } 01031 iv_put(mrb, t, sym, v); 01032 } 01033 01034 MRB_API void 01035 mrb_gv_remove(mrb_state *mrb, mrb_sym sym) 01036 { 01037 if (!mrb->globals) { 01038 return; 01039 } 01040 iv_del(mrb, mrb->globals, sym, NULL); 01041 } 01042 01043 static int 01044 gv_i(mrb_state *mrb, mrb_sym sym, mrb_value v, void *p) 01045 { 01046 mrb_value ary; 01047 01048 ary = *(mrb_value*)p; 01049 mrb_ary_push(mrb, ary, mrb_symbol_value(sym)); 01050 return 0; 01051 } 01052 01053 /* 15.3.1.2.4 */ 01054 /* 15.3.1.3.14 */ 01055 /* 01056 * call-seq: 01057 * global_variables -> array 01058 * 01059 * Returns an array of the names of global variables. 01060 * 01061 * global_variables.grep /std/ #=> [:$stdin, :$stdout, :$stderr] 01062 */ 01063 mrb_value 01064 mrb_f_global_variables(mrb_state *mrb, mrb_value self) 01065 { 01066 iv_tbl *t = mrb->globals; 01067 mrb_value ary = mrb_ary_new(mrb); 01068 size_t i; 01069 char buf[3]; 01070 01071 if (t) { 01072 iv_foreach(mrb, t, gv_i, &ary); 01073 } 01074 buf[0] = '$'; 01075 buf[2] = 0; 01076 for (i = 1; i <= 9; ++i) { 01077 buf[1] = (char)(i + '0'); 01078 mrb_ary_push(mrb, ary, mrb_symbol_value(mrb_intern(mrb, buf, 2))); 01079 } 01080 return ary; 01081 } 01082 01083 static mrb_bool 01084 mrb_const_defined_0(mrb_state *mrb, mrb_value mod, mrb_sym id, mrb_bool exclude, mrb_bool recurse) 01085 { 01086 struct RClass *klass = mrb_class_ptr(mod); 01087 struct RClass *tmp; 01088 mrb_bool mod_retry = 0; 01089 01090 tmp = klass; 01091 retry: 01092 while (tmp) { 01093 if (tmp->iv && iv_get(mrb, tmp->iv, id, NULL)) { 01094 return TRUE; 01095 } 01096 if (!recurse && (klass != mrb->object_class)) break; 01097 tmp = tmp->super; 01098 } 01099 if (!exclude && !mod_retry && (klass->tt == MRB_TT_MODULE)) { 01100 mod_retry = 1; 01101 tmp = mrb->object_class; 01102 goto retry; 01103 } 01104 return FALSE; 01105 } 01106 01107 MRB_API mrb_bool 01108 mrb_const_defined(mrb_state *mrb, mrb_value mod, mrb_sym id) 01109 { 01110 return mrb_const_defined_0(mrb, mod, id, TRUE, TRUE); 01111 } 01112 01113 MRB_API mrb_bool 01114 mrb_const_defined_at(mrb_state *mrb, mrb_value mod, mrb_sym id) 01115 { 01116 return mrb_const_defined_0(mrb, mod, id, TRUE, FALSE); 01117 } 01118 01119 MRB_API mrb_value 01120 mrb_attr_get(mrb_state *mrb, mrb_value obj, mrb_sym id) 01121 { 01122 return mrb_iv_get(mrb, obj, id); 01123 } 01124 01125 struct csym_arg { 01126 struct RClass *c; 01127 mrb_sym sym; 01128 }; 01129 01130 static int 01131 csym_i(mrb_state *mrb, mrb_sym sym, mrb_value v, void *p) 01132 { 01133 struct csym_arg *a = (struct csym_arg*)p; 01134 struct RClass *c = a->c; 01135 01136 if (mrb_type(v) == c->tt && mrb_class_ptr(v) == c) { 01137 a->sym = sym; 01138 return 1; /* stop iteration */ 01139 } 01140 return 0; 01141 } 01142 01143 mrb_sym 01144 mrb_class_sym(mrb_state *mrb, struct RClass *c, struct RClass *outer) 01145 { 01146 mrb_value name; 01147 01148 name = mrb_obj_iv_get(mrb, (struct RObject*)c, mrb_intern_lit(mrb, "__classid__")); 01149 if (mrb_nil_p(name)) { 01150 01151 if (!outer) return 0; 01152 else { 01153 struct csym_arg arg; 01154 01155 arg.c = c; 01156 arg.sym = 0; 01157 iv_foreach(mrb, outer->iv, csym_i, &arg); 01158 return arg.sym; 01159 } 01160 } 01161 return mrb_symbol(name); 01162 } 01163
Generated on Tue Jul 12 2022 18:00:35 by 1.7.2