diff options
Diffstat (limited to 'src/variable.c')
| -rw-r--r-- | src/variable.c | 453 |
1 files changed, 453 insertions, 0 deletions
diff --git a/src/variable.c b/src/variable.c new file mode 100644 index 000000000..0bc1f0de1 --- /dev/null +++ b/src/variable.c @@ -0,0 +1,453 @@ +#include "mruby.h" +#include "mruby/class.h" +#include "ritehash.h" +#include "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)); +} + |
