mbed I/F binding for mruby

Dependents:   mruby_mbed_web mirb_mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers variable.c Source File

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