/* ** variable.c - mruby variables ** ** See Copyright Notice in mruby.h */ #include #include "mruby.h" #include "mruby/class.h" #include "mruby/khash.h" #include "mruby/variable.h" #include "mruby/string.h" #include "mruby/range.h" #include "error.h" #include "mruby/array.h" #ifdef INCLUDE_REGEXP #include "re.h" #include "st.h" #endif KHASH_MAP_INIT_INT(iv, mrb_value); #ifndef FALSE #define FALSE 0 #endif #ifndef TRUE #define TRUE 1 #endif static void mark_tbl(mrb_state *mrb, struct kh_iv *h) { khiter_t k; if (!h) return; for (k = kh_begin(h); k != kh_end(h); k++) if (kh_exist(h, k)) mrb_gc_mark_value(mrb, kh_value(h, k)); } void mrb_gc_mark_gv(mrb_state *mrb) { mark_tbl(mrb, mrb->globals); } void mrb_gc_free_gv(mrb_state *mrb) { kh_destroy(iv, mrb->globals); } void mrb_gc_mark_iv(mrb_state *mrb, struct RObject *obj) { mark_tbl(mrb, obj->iv); } size_t mrb_gc_mark_iv_size(mrb_state *mrb, struct RObject *obj) { khiter_t k; struct kh_iv *h = obj->iv; if (!h) return 0; return kh_size(h); } void mrb_gc_free_iv(mrb_state *mrb, struct RObject *obj) { kh_destroy(iv, obj->iv); } mrb_value mrb_vm_special_get(mrb_state *mrb, mrb_sym i) { return mrb_fixnum_value(0); } void mrb_vm_special_set(mrb_state *mrb, mrb_sym i, mrb_value v) { } static mrb_value ivget(mrb_state *mrb, struct kh_iv *h, mrb_sym sym) { khiter_t k; k = kh_get(iv, h, sym); if (k != kh_end(h)) return kh_value(h, k); return mrb_nil_value(); } mrb_value mrb_obj_iv_get(mrb_state *mrb, struct RObject *obj, mrb_sym sym) { if (!obj->iv) { return mrb_nil_value(); } return ivget(mrb, obj->iv, sym); } mrb_value mrb_iv_get(mrb_state *mrb, mrb_value obj, mrb_sym sym) { return mrb_obj_iv_get(mrb, mrb_obj_ptr(obj), sym); } static void ivset(mrb_state *mrb, struct kh_iv *h, mrb_sym sym, mrb_value v) { khiter_t k; int r; k = kh_put(iv, h, sym, &r); kh_value(h, k) = v; } void mrb_obj_iv_set(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v) { khash_t(iv) *h; if (!obj->iv) { h = obj->iv = kh_init(iv, mrb); } else { h = obj->iv; } mrb_write_barrier(mrb, (struct RBasic*)obj); ivset(mrb, h, sym, v); } void mrb_iv_set(mrb_state *mrb, mrb_value obj, mrb_sym sym, mrb_value v) /* mrb_ivar_set */ { mrb_obj_iv_set(mrb, mrb_obj_ptr(obj), sym, v); } mrb_value mrb_vm_iv_get(mrb_state *mrb, mrb_sym sym) { /* get self */ return mrb_iv_get(mrb, mrb->stack[0], sym); } void mrb_vm_iv_set(mrb_state *mrb, mrb_sym sym, mrb_value v) { /* get self */ mrb_iv_set(mrb, mrb->stack[0], sym, v); } mrb_value mrb_vm_cv_get(mrb_state *mrb, mrb_sym sym) { struct RClass *c = mrb->ci->target_class; while (c) { if (c->iv) { khash_t(iv) *h = c->iv; khiter_t k = kh_get(iv, h, sym); if (k != kh_end(h)) return kh_value(h, k); } c = c->super; } return mrb_nil_value(); } void mrb_vm_cv_set(mrb_state *mrb, mrb_sym sym, mrb_value v) { struct RClass *c = mrb->ci->target_class; khash_t(iv) *h; khiter_t k; int r; while (c) { if (c->iv) { h = c->iv; k = kh_get(iv, h, sym); if (k != kh_end(h)) { k = kh_put(iv, h, sym, &r); kh_value(h, k) = v; } } c = c->super; } c = mrb->ci->target_class; h = c->iv = kh_init(iv, mrb); k = kh_put(iv, h, sym, &r); kh_value(h, k) = v; } int mrb_const_defined(mrb_state *mrb, mrb_value mod, mrb_sym sym) { khiter_t k; struct RClass *m = mrb_class_ptr(mod); struct kh_iv *h = m->iv; if (!h) return 0; k = kh_get(iv, h, sym); if (k != kh_end(h)) return 1; return 0; } static void mod_const_check(mrb_state *mrb, mrb_value mod) { switch (mod.tt) { case MRB_TT_CLASS: case MRB_TT_MODULE: break; default: mrb_raise(mrb, E_TYPE_ERROR, "constant look-up for non class/module"); break; } } static mrb_value const_get(mrb_state *mrb, struct RClass *base, mrb_sym sym) { struct RClass *c = base; khash_t(iv) *h; khiter_t k; if (c->iv) { h = c->iv; k = kh_get(iv, h, sym); if (k != kh_end(h)) { return kh_value(h, k); } } for (;;) { c = mrb_class_outer_module(mrb, c); if (!c) break; if (c->iv) { h = c->iv; k = kh_get(iv, h, sym); if (k != kh_end(h)) { return kh_value(h, k); } } } c = base->super; while (c) { if (c->iv) { h = c->iv; k = kh_get(iv, h, sym); if (k != kh_end(h)) { return kh_value(h, k); } } c = c->super; } mrb_raise(mrb, E_NAME_ERROR, "uninitialized constant %s", mrb_sym2name(mrb, sym)); /* not reached */ return mrb_nil_value(); } mrb_value mrb_const_get(mrb_state *mrb, mrb_value mod, mrb_sym sym) { mod_const_check(mrb, mod); return const_get(mrb, mrb_class_ptr(mod), sym); } mrb_value mrb_vm_const_get(mrb_state *mrb, mrb_sym sym) { return const_get(mrb, mrb->ci->target_class, sym); } void mrb_const_set(mrb_state *mrb, mrb_value mod, mrb_sym sym, mrb_value v) { mod_const_check(mrb, mod); mrb_iv_set(mrb, mod, sym, v); } void mrb_vm_const_set(mrb_state *mrb, mrb_sym sym, mrb_value v) { mrb_obj_iv_set(mrb, (struct RObject*)mrb->ci->target_class, sym, v); } void mrb_define_const(mrb_state *mrb, struct RClass *mod, const char *name, mrb_value v) { mrb_obj_iv_set(mrb, (struct RObject*)mod, mrb_intern(mrb, name), v); } void mrb_define_global_const(mrb_state *mrb, const char *name, mrb_value val) { mrb_define_const(mrb, mrb->object_class, name, val); } mrb_value mrb_gv_get(mrb_state *mrb, mrb_sym sym) { if (!mrb->globals) { return mrb_nil_value(); } return ivget(mrb, mrb->globals, sym); } void mrb_gv_set(mrb_state *mrb, mrb_sym sym, mrb_value v) { khash_t(iv) *h; if (!mrb->globals) { h = mrb->globals = kh_init(iv, mrb); } else { h = mrb->globals; } ivset(mrb, h, sym, v); } /* 15.3.1.2.4 */ /* 15.3.1.3.14 */ /* * call-seq: * global_variables -> array * * Returns an array of the names of global variables. * * global_variables.grep /std/ #=> [:$stdin, :$stdout, :$stderr] */ mrb_value mrb_f_global_variables(mrb_state *mrb, mrb_value self) { char buf[3]; int i; struct kh_iv *h = mrb->globals; mrb_value ary = mrb_ary_new(mrb); for (i=0;i< kh_end(h);i++) { if (kh_exist(h, i)) { mrb_ary_push(mrb, ary, mrb_symbol_value(kh_key(h,i))); } } buf[0] = '$'; buf[2] = 0; for (i = 1; i <= 9; ++i) { buf[1] = (char)(i + '0'); mrb_ary_push(mrb, ary, mrb_symbol_value(mrb_intern(mrb, buf))); } return ary; } int mrb_st_lookup(struct kh_iv *table, mrb_sym id, khiter_t *value) { khash_t(iv) *h; khiter_t k; if (table) { h = (khash_t(iv) *)table; k = kh_get(iv, h, id); if (k != kh_end(h)) { if (value != 0) *value = k;//kh_value(h, k); return 1;/* TRUE */ } return 0;/* FALSE */ } else { return 0;/* FALSE */ } } int kiv_lookup(khash_t(iv)* table, mrb_sym key, mrb_value *value) { khash_t(iv) *h=table; khiter_t k; // you must check(iv==0), before you call this function. //if (!obj->iv) { // return 0; //} k = kh_get(iv, h, key); if (k != kh_end(h)) { *value = kh_value(h, k); return 1; } return 0; } static int mrb_const_defined_0(mrb_state *mrb, struct RClass *klass, mrb_sym id, int exclude, int recurse) { mrb_value value; struct RClass * tmp; int mod_retry = 0; tmp = klass; retry: while (tmp) { if (tmp->iv && kiv_lookup(tmp->iv, id, &value)) { return (int)1/*Qtrue*/; } if (!recurse && (klass != mrb->object_class)) break; tmp = tmp->super; } if (!exclude && !mod_retry && (klass->tt == MRB_TT_MODULE)) { mod_retry = 1; tmp = mrb->object_class; goto retry; } return (int)0/*Qfalse*/; } int mrb_const_defined_at(mrb_state *mrb, struct RClass *klass, mrb_sym id) { return mrb_const_defined_0(mrb, klass, id, TRUE, FALSE); } struct RClass * mrb_class_from_sym(mrb_state *mrb, struct RClass *klass, mrb_sym id) { mrb_value c = const_get(mrb, klass, id); return mrb_class_ptr(c); } struct RClass * mrb_class_get(mrb_state *mrb, char *name) { return mrb_class_from_sym(mrb, mrb->object_class, mrb_intern(mrb, name)); } mrb_value mrb_attr_get(mrb_state *mrb, mrb_value obj, mrb_sym id) { //return ivar_get(obj, id, FALSE); return mrb_iv_get(mrb, obj, id); } struct RClass * mrb_class_obj_get(mrb_state *mrb, char *name) { mrb_value mod = mrb_obj_value(mrb->object_class); mrb_sym sym = mrb_intern(mrb, name); return mrb_class_ptr(mrb_const_get(mrb, mod, sym)); }