diff options
Diffstat (limited to 'src/variable.c')
| -rw-r--r-- | src/variable.c | 912 |
1 files changed, 446 insertions, 466 deletions
diff --git a/src/variable.c b/src/variable.c index c4f6fb830..d89295229 100644 --- a/src/variable.c +++ b/src/variable.c @@ -4,392 +4,234 @@ ** See Copyright Notice in mruby.h */ -#include <ctype.h> -#include "mruby.h" -#include "mruby/array.h" -#include "mruby/class.h" -#include "mruby/proc.h" -#include "mruby/string.h" - -typedef int (iv_foreach_func)(mrb_state*,mrb_sym,mrb_value,void*); - -#ifdef MRB_USE_IV_SEGLIST - -#ifndef MRB_SEGMENT_SIZE -#define MRB_SEGMENT_SIZE 4 -#endif - -typedef struct segment { - mrb_sym key[MRB_SEGMENT_SIZE]; - mrb_value val[MRB_SEGMENT_SIZE]; - struct segment *next; -} segment; +#include <mruby.h> +#include <mruby/array.h> +#include <mruby/class.h> +#include <mruby/proc.h> +#include <mruby/string.h> +#include <mruby/variable.h> +#include <mruby/presym.h> + +struct iv_elem { + mrb_sym key; + mrb_value val; +}; /* Instance variable table structure */ typedef struct iv_tbl { - segment *rootseg; size_t size; - size_t last_len; + size_t alloc; + struct iv_elem *table; } iv_tbl; -/* - * Creates the instance variable table. - * - * Parameters - * mrb - * Returns - * the instance variable table. - */ +/* Creates the instance variable table. */ static iv_tbl* iv_new(mrb_state *mrb) { iv_tbl *t; - t = mrb_malloc(mrb, sizeof(iv_tbl)); + t = (iv_tbl*)mrb_malloc(mrb, sizeof(iv_tbl)); t->size = 0; - t->rootseg = NULL; - t->last_len = 0; + t->alloc = 0; + t->table = NULL; return t; } -/* - * Set the value for the symbol in the instance variable table. - * - * Parameters - * mrb - * t the instance variable table to be set in. - * sym the symbol to be used as the key. - * val the value to be set. - */ +static void iv_put(mrb_state *mrb, iv_tbl *t, mrb_sym sym, mrb_value val); + static void -iv_put(mrb_state *mrb, iv_tbl *t, mrb_sym sym, mrb_value val) +iv_rehash(mrb_state *mrb, iv_tbl *t) { - segment *seg = t->rootseg; - segment *prev = NULL; - segment *matched_seg = NULL; - size_t matched_idx = 0; - size_t i; + size_t old_alloc = t->alloc; + size_t new_alloc = old_alloc+1; + struct iv_elem *old_table = t->table; - while (seg) { - for (i=0; i<MRB_SEGMENT_SIZE; i++) { - mrb_sym key = seg->key[i]; - /* Found room in last segment after last_len */ - if (!seg->next && i >= t->last_len) { - seg->key[i] = sym; - seg->val[i] = val; - t->last_len = i+1; - t->size++; - return; - } - if (!matched_seg && key == 0) { - matched_seg = seg; - matched_idx = i; - } - else if (key == sym) { - seg->val[i] = val; - return; - } + khash_power2(new_alloc); + if (old_alloc == new_alloc) return; + + t->alloc = new_alloc; + t->size = 0; + t->table = (struct iv_elem*)mrb_calloc(mrb, sizeof(struct iv_elem), new_alloc); + + for (size_t i = 0; i < old_alloc; i++) { + struct iv_elem *slot = &old_table[i]; + + /* key = 0 means empty; val = undef means deleted */ + if (slot->key != 0 && !mrb_undef_p(slot->val)) { + iv_put(mrb, t, slot->key, slot->val); } - prev = seg; - seg = seg->next; } + mrb_free(mrb, old_table); +} - /* Not found */ - t->size++; - if (matched_seg) { - matched_seg->key[matched_idx] = sym; - matched_seg->val[matched_idx] = val; - return; - } +#define slot_empty_p(slot) ((slot)->key == 0 && !mrb_undef_p((slot)->val)) - seg = mrb_malloc(mrb, sizeof(segment)); - if (!seg) return; - seg->next = NULL; - seg->key[0] = sym; - seg->val[0] = val; - t->last_len = 1; - if (prev) { - prev->next = seg; +/* Set the value for the symbol in the instance variable table. */ +static void +iv_put(mrb_state *mrb, iv_tbl *t, mrb_sym sym, mrb_value val) +{ + size_t hash, pos, start; + struct iv_elem *dslot = NULL; + + if (t == NULL) return; + if (t->alloc == 0) { + iv_rehash(mrb, t); } - else { - t->rootseg = seg; + hash = kh_int_hash_func(mrb, sym); + start = pos = hash & (t->alloc-1); + for (;;) { + struct iv_elem *slot = &t->table[pos]; + + if (slot->key == sym) { + slot->val = val; + return; + } + else if (slot_empty_p(slot)) { + t->size++; + slot->key = sym; + slot->val = val; + return; + } + else if (!dslot && mrb_undef_p(slot->val)) { /* deleted */ + dslot = slot; + } + pos = (pos+1) & (t->alloc-1); + if (pos == start) { /* not found */ + if (dslot) { + t->size++; + dslot->key = sym; + dslot->val = val; + return; + } + /* no room */ + iv_rehash(mrb, t); + start = pos = hash & (t->alloc-1); + } } } -/* - * Get a value for a symbol from the instance variable table. - * - * Parameters - * mrb - * t the variable table to be searched. - * sym the symbol to be used as the key. - * vp the value pointer. Receives the value if the specified symbol is - * contained in the instance variable table. - * Returns - * true if the specified symbol is contained in the instance variable table. - */ +/* Get a value for a symbol from the instance variable table. */ static mrb_bool iv_get(mrb_state *mrb, iv_tbl *t, mrb_sym sym, mrb_value *vp) { - segment *seg; - size_t i; + size_t hash, pos, start; - seg = t->rootseg; - while (seg) { - for (i=0; i<MRB_SEGMENT_SIZE; i++) { - mrb_sym key = seg->key[i]; + if (t == NULL) return FALSE; + if (t->alloc == 0) return FALSE; + if (t->size == 0) return FALSE; - if (!seg->next && i >= t->last_len) { - return FALSE; - } - if (key == sym) { - if (vp) *vp = seg->val[i]; - return TRUE; - } + hash = kh_int_hash_func(mrb, sym); + start = pos = hash & (t->alloc-1); + for (;;) { + struct iv_elem *slot = &t->table[pos]; + + if (slot->key == sym) { + if (vp) *vp = slot->val; + return TRUE; + } + else if (slot_empty_p(slot)) { + return FALSE; + } + pos = (pos+1) & (t->alloc-1); + if (pos == start) { /* not found */ + return FALSE; } - seg = seg->next; } - return FALSE; } -/* - * Deletes the value for the symbol from the instance variable table. - * - * Parameters - * t the variable table to be searched. - * sym the symbol to be used as the key. - * vp the value pointer. Receive the deleted value if the symbol is - * contained in the instance variable table. - * Returns - * true if the specified symbol is contained in the instance variable table. - */ +/* Deletes the value for the symbol from the instance variable table. */ static mrb_bool iv_del(mrb_state *mrb, iv_tbl *t, mrb_sym sym, mrb_value *vp) { - segment *seg; - size_t i; + size_t hash, pos, start; - seg = t->rootseg; - while (seg) { - for (i=0; i<MRB_SEGMENT_SIZE; i++) { - mrb_sym key = seg->key[i]; + if (t == NULL) return FALSE; + if (t->alloc == 0) return FALSE; + if (t->size == 0) return FALSE; - if (!seg->next && i >= t->last_len) { - return FALSE; - } - if (key == sym) { - t->size--; - seg->key[i] = 0; - if (vp) *vp = seg->val[i]; - return TRUE; - } + hash = kh_int_hash_func(mrb, sym); + start = pos = hash & (t->alloc-1); + for (;;) { + struct iv_elem *slot = &t->table[pos]; + + if (slot->key == sym) { + if (vp) *vp = slot->val; + t->size--; + slot->key = 0; + slot->val = mrb_undef_value(); + return TRUE; + } + else if (slot_empty_p(slot)) { + return FALSE; + } + pos = (pos+1) & (t->alloc-1); + if (pos == start) { /* not found */ + return FALSE; } - seg = seg->next; } - return FALSE; } -static mrb_bool -iv_foreach(mrb_state *mrb, iv_tbl *t, iv_foreach_func *func, void *p) +/* Iterates over the instance variable table. */ +static void +iv_foreach(mrb_state *mrb, iv_tbl *t, mrb_iv_foreach_func *func, void *p) { - segment *seg; size_t i; - int n; - seg = t->rootseg; - while (seg) { - for (i=0; i<MRB_SEGMENT_SIZE; i++) { - mrb_sym key = seg->key[i]; + if (t == NULL) return; + if (t->alloc == 0) return; + if (t->size == 0) return; - /* no value in last segment after last_len */ - if (!seg->next && i >= t->last_len) { - return FALSE; - } - if (key != 0) { - n =(*func)(mrb, key, seg->val[i], p); - if (n > 0) return FALSE; - if (n < 0) { - t->size--; - seg->key[i] = 0; - } + for (i=0; i<t->alloc; i++) { + struct iv_elem *slot = &t->table[i]; + + if (slot->key && !mrb_undef_p(slot->val)) { + if ((*func)(mrb, slot->key, slot->val, p) != 0) { + return; } } - seg = seg->next; } - return TRUE; + return; } +/* Get the size of the instance variable table. */ static size_t iv_size(mrb_state *mrb, iv_tbl *t) { - segment *seg; - size_t size = 0; - - if (!t) return 0; - if (t->size > 0) return t->size; - seg = t->rootseg; - while (seg) { - if (seg->next == NULL) { - size += t->last_len; - return size; - } - seg = seg->next; - size += MRB_SEGMENT_SIZE; - } - /* empty iv_tbl */ - return 0; + if (t == NULL) return 0; + return t->size; } +/* Copy the instance variable table. */ static iv_tbl* iv_copy(mrb_state *mrb, iv_tbl *t) { - segment *seg; iv_tbl *t2; - size_t i; - seg = t->rootseg; - t2 = iv_new(mrb); + if (t == NULL) return NULL; + if (t->alloc == 0) return NULL; + if (t->size == 0) return NULL; - while (seg != NULL) { - for (i=0; i<MRB_SEGMENT_SIZE; i++) { - mrb_sym key = seg->key[i]; - mrb_value val = seg->val[i]; + t2 = iv_new(mrb); + for (i=0; i<t->alloc; i++) { + struct iv_elem *slot = &t->table[i]; - if ((seg->next == NULL) && (i >= t->last_len)) { - return t2; - } - iv_put(mrb, t2, key, val); + if (slot->key && !mrb_undef_p(slot->val)) { + iv_put(mrb, t2, slot->key, slot->val); } - seg = seg->next; } return t2; } +/* Free memory of the instance variable table. */ static void iv_free(mrb_state *mrb, iv_tbl *t) { - segment *seg; - - seg = t->rootseg; - while (seg) { - segment *p = seg; - seg = seg->next; - mrb_free(mrb, p); - } + mrb_free(mrb, t->table); mrb_free(mrb, t); } -#else - -#include "mruby/khash.h" - -#ifndef MRB_IVHASH_INIT_SIZE -#define MRB_IVHASH_INIT_SIZE 8 -#endif - -KHASH_DECLARE(iv, mrb_sym, mrb_value, TRUE) -KHASH_DEFINE(iv, mrb_sym, mrb_value, TRUE, kh_int_hash_func, kh_int_hash_equal) - -typedef struct iv_tbl { - khash_t(iv) h; -} iv_tbl; - -static iv_tbl* -iv_new(mrb_state *mrb) -{ - return (iv_tbl*)kh_init_size(iv, mrb, MRB_IVHASH_INIT_SIZE); -} - -static void -iv_put(mrb_state *mrb, iv_tbl *t, mrb_sym sym, mrb_value val) -{ - khash_t(iv) *h = &t->h; - khiter_t k; - - k = kh_put(iv, mrb, h, sym); - kh_value(h, k) = val; -} - -static mrb_bool -iv_get(mrb_state *mrb, iv_tbl *t, mrb_sym sym, mrb_value *vp) -{ - khash_t(iv) *h = &t->h; - khiter_t k; - - k = kh_get(iv, mrb, h, sym); - if (k != kh_end(h)) { - if (vp) *vp = kh_value(h, k); - return TRUE; - } - return FALSE; -} - -static mrb_bool -iv_del(mrb_state *mrb, iv_tbl *t, mrb_sym sym, mrb_value *vp) -{ - khash_t(iv) *h = &t->h; - khiter_t k; - - if (h) { - k = kh_get(iv, mrb, h, sym); - if (k != kh_end(h)) { - mrb_value val = kh_value(h, k); - kh_del(iv, mrb, h, k); - if (vp) *vp = val; - return TRUE; - } - } - return FALSE; -} - -static mrb_bool -iv_foreach(mrb_state *mrb, iv_tbl *t, iv_foreach_func *func, void *p) -{ - khash_t(iv) *h = &t->h; - khiter_t k; - int n; - - if (h) { - for (k = kh_begin(h); k != kh_end(h); k++) { - if (kh_exist(h, k)) { - n = (*func)(mrb, kh_key(h, k), kh_value(h, k), p); - if (n > 0) return FALSE; - if (n < 0) { - kh_del(iv, mrb, h, k); - } - } - } - } - return TRUE; -} - -static size_t -iv_size(mrb_state *mrb, iv_tbl *t) -{ - khash_t(iv) *h; - - if (t && (h = &t->h)) { - return kh_size(h); - } - return 0; -} - -static iv_tbl* -iv_copy(mrb_state *mrb, iv_tbl *t) -{ - return (iv_tbl*)kh_copy(iv, mrb, &t->h); -} - -static void -iv_free(mrb_state *mrb, iv_tbl *t) -{ - kh_destroy(iv, mrb, &t->h); -} - -#endif - static int iv_mark_i(mrb_state *mrb, mrb_sym sym, mrb_value v, void *p) { @@ -400,9 +242,7 @@ iv_mark_i(mrb_state *mrb, mrb_sym sym, mrb_value v, void *p) static void mark_tbl(mrb_state *mrb, iv_tbl *t) { - if (t) { - iv_foreach(mrb, t, iv_mark_i, 0); - } + iv_foreach(mrb, t, iv_mark_i, 0); } void @@ -485,31 +325,64 @@ mrb_iv_get(mrb_state *mrb, mrb_value obj, mrb_sym sym) return mrb_nil_value(); } +static inline void assign_class_name(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v); + +void +mrb_obj_iv_set_force(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v) +{ + assign_class_name(mrb, obj, sym, v); + if (!obj->iv) { + obj->iv = iv_new(mrb); + } + iv_put(mrb, obj->iv, sym, v); + mrb_field_write_barrier_value(mrb, (struct RBasic*)obj, v); +} + MRB_API void mrb_obj_iv_set(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v) { - iv_tbl *t = obj->iv; - - if (!t) { - t = obj->iv = iv_new(mrb); - } - mrb_write_barrier(mrb, (struct RBasic*)obj); - iv_put(mrb, t, sym, v); + mrb_check_frozen(mrb, obj); + mrb_obj_iv_set_force(mrb, obj, sym, v); } +/* Iterates over the instance variable table. */ MRB_API void -mrb_obj_iv_ifnone(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v) +mrb_iv_foreach(mrb_state *mrb, mrb_value obj, mrb_iv_foreach_func *func, void *p) { - iv_tbl *t = obj->iv; + if (!obj_iv_p(obj)) return; + iv_foreach(mrb, mrb_obj_ptr(obj)->iv, func, p); +} - if (!t) { - t = obj->iv = iv_new(mrb); - } - else if (iv_get(mrb, t, sym, &v)) { - return; +static inline mrb_bool +namespace_p(enum mrb_vtype tt) +{ + return tt == MRB_TT_CLASS || tt == MRB_TT_MODULE ? TRUE : FALSE; +} + +static inline void +assign_class_name(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v) +{ + if (namespace_p(obj->tt) && namespace_p(mrb_type(v))) { + struct RObject *c = mrb_obj_ptr(v); + if (obj != c && ISUPPER(mrb_sym_name_len(mrb, sym, NULL)[0])) { + mrb_sym id_classname = MRB_SYM(__classname__); + mrb_value o = mrb_obj_iv_get(mrb, c, id_classname); + + if (mrb_nil_p(o)) { + mrb_sym id_outer = MRB_SYM(__outer__); + o = mrb_obj_iv_get(mrb, c, id_outer); + + if (mrb_nil_p(o)) { + if ((struct RClass *)obj == mrb->object_class) { + mrb_obj_iv_set_force(mrb, c, id_classname, mrb_symbol_value(sym)); + } + else { + mrb_obj_iv_set_force(mrb, c, id_outer, mrb_obj_value(obj)); + } + } + } + } } - mrb_write_barrier(mrb, (struct RBasic*)obj); - iv_put(mrb, t, sym, v); } MRB_API void @@ -542,29 +415,24 @@ mrb_iv_defined(mrb_state *mrb, mrb_value obj, mrb_sym sym) return mrb_obj_iv_defined(mrb, mrb_obj_ptr(obj), sym); } -#define identchar(c) (ISALNUM(c) || (c) == '_' || !ISASCII(c)) - MRB_API mrb_bool -mrb_iv_p(mrb_state *mrb, mrb_sym iv_name) +mrb_iv_name_sym_p(mrb_state *mrb, mrb_sym iv_name) { const char *s; - mrb_int i, len; + mrb_int len; - s = mrb_sym2name_len(mrb, iv_name, &len); + s = mrb_sym_name_len(mrb, iv_name, &len); if (len < 2) return FALSE; if (s[0] != '@') return FALSE; - if (s[1] == '@') return FALSE; - for (i=1; i<len; i++) { - if (!identchar(s[i])) return FALSE; - } - return TRUE; + if (ISDIGIT(s[1])) return FALSE; + return mrb_ident_p(s+1, len-1); } MRB_API void -mrb_iv_check(mrb_state *mrb, mrb_sym iv_name) +mrb_iv_name_sym_check(mrb_state *mrb, mrb_sym iv_name) { - if (!mrb_iv_p(mrb, iv_name)) { - mrb_name_error(mrb, iv_name, "`%S' is not allowed as an instance variable name", mrb_sym2str(mrb, iv_name)); + if (!mrb_iv_name_sym_p(mrb, iv_name)) { + mrb_name_error(mrb, iv_name, "'%n' is not allowed as an instance variable name", iv_name); } } @@ -601,16 +469,16 @@ inspect_i(mrb_state *mrb, mrb_sym sym, mrb_value v, void *p) else { mrb_str_cat_lit(mrb, str, ", "); } - s = mrb_sym2name_len(mrb, sym, &len); + s = mrb_sym_name_len(mrb, sym, &len); mrb_str_cat(mrb, str, s, len); mrb_str_cat_lit(mrb, str, "="); - if (mrb_type(v) == MRB_TT_OBJECT) { + if (mrb_object_p(v)) { ins = mrb_any_to_s(mrb, v); } else { ins = mrb_inspect(mrb, v); } - mrb_str_append(mrb, str, ins); + mrb_str_cat_str(mrb, str, ins); return 0; } @@ -622,12 +490,12 @@ mrb_obj_iv_inspect(mrb_state *mrb, struct RObject *obj) if (len > 0) { const char *cn = mrb_obj_classname(mrb, mrb_obj_value(obj)); - mrb_value str = mrb_str_buf_new(mrb, 30); + mrb_value str = mrb_str_new_capa(mrb, 30); mrb_str_cat_lit(mrb, str, "-<"); mrb_str_cat_cstr(mrb, str, cn); mrb_str_cat_lit(mrb, str, ":"); - mrb_str_concat(mrb, str, mrb_ptr_to_str(mrb, obj)); + mrb_str_cat_str(mrb, str, mrb_ptr_to_str(mrb, obj)); iv_foreach(mrb, t, inspect_i, &str); mrb_str_cat_lit(mrb, str, ">"); @@ -643,27 +511,14 @@ mrb_iv_remove(mrb_state *mrb, mrb_value obj, mrb_sym sym) iv_tbl *t = mrb_obj_ptr(obj)->iv; mrb_value val; - if (t && iv_del(mrb, t, sym, &val)) { + mrb_check_frozen(mrb, mrb_obj_ptr(obj)); + if (iv_del(mrb, t, sym, &val)) { return val; } } return mrb_undef_value(); } -mrb_value -mrb_vm_iv_get(mrb_state *mrb, mrb_sym sym) -{ - /* get self */ - return mrb_iv_get(mrb, mrb->c->stack[0], sym); -} - -void -mrb_vm_iv_set(mrb_state *mrb, mrb_sym sym, mrb_value v) -{ - /* get self */ - mrb_iv_set(mrb, mrb->c->stack[0], sym, v); -} - static int iv_i(mrb_state *mrb, mrb_sym sym, mrb_value v, void *p) { @@ -672,7 +527,7 @@ iv_i(mrb_state *mrb, mrb_sym sym, mrb_value v, void *p) mrb_int len; ary = *(mrb_value*)p; - s = mrb_sym2name_len(mrb, sym, &len); + s = mrb_sym_name_len(mrb, sym, &len); if (len > 1 && s[0] == '@' && s[1] != '@') { mrb_ary_push(mrb, ary, mrb_symbol_value(sym)); } @@ -702,7 +557,7 @@ mrb_obj_instance_variables(mrb_state *mrb, mrb_value self) mrb_value ary; ary = mrb_ary_new(mrb); - if (obj_iv_p(self) && mrb_obj_ptr(self)->iv) { + if (obj_iv_p(self)) { iv_foreach(mrb, mrb_obj_ptr(self)->iv, iv_i, &ary); } return ary; @@ -716,7 +571,7 @@ cv_i(mrb_state *mrb, mrb_sym sym, mrb_value v, void *p) mrb_int len; ary = *(mrb_value*)p; - s = mrb_sym2name_len(mrb, sym, &len); + s = mrb_sym_name_len(mrb, sym, &len); if (len > 2 && s[0] == '@' && s[1] == '@') { mrb_ary_push(mrb, ary, mrb_symbol_value(sym)); } @@ -726,7 +581,7 @@ cv_i(mrb_state *mrb, mrb_sym sym, mrb_value v, void *p) /* 15.2.2.4.19 */ /* * call-seq: - * mod.class_variables -> array + * mod.class_variables(inherit=true) -> array * * Returns an array of the names of class variables in <i>mod</i>. * @@ -744,35 +599,50 @@ mrb_mod_class_variables(mrb_state *mrb, mrb_value mod) { mrb_value ary; struct RClass *c; + mrb_bool inherit = TRUE; + mrb_get_args(mrb, "|b", &inherit); ary = mrb_ary_new(mrb); c = mrb_class_ptr(mod); while (c) { - if (c->iv) { - iv_foreach(mrb, c->iv, cv_i, &ary); - } + iv_foreach(mrb, c->iv, cv_i, &ary); + if (!inherit) break; c = c->super; } return ary; } -MRB_API mrb_value -mrb_mod_cv_get(mrb_state *mrb, struct RClass * c, mrb_sym sym) +mrb_value +mrb_mod_cv_get(mrb_state *mrb, struct RClass *c, mrb_sym sym) { struct RClass * cls = c; + mrb_value v; + int given = FALSE; while (c) { - if (c->iv) { - iv_tbl *t = c->iv; - mrb_value v; - - if (iv_get(mrb, t, sym, &v)) - return v; + if (c->iv && iv_get(mrb, c->iv, sym, &v)) { + given = TRUE; } c = c->super; } - mrb_name_error(mrb, sym, "uninitialized class variable %S in %S", - mrb_sym2str(mrb, sym), mrb_obj_value(cls)); + if (given) return v; + if (cls && cls->tt == MRB_TT_SCLASS) { + mrb_value klass; + + klass = mrb_obj_iv_get(mrb, (struct RObject *)cls, MRB_SYM(__attached__)); + c = mrb_class_ptr(klass); + if (c->tt == MRB_TT_CLASS || c->tt == MRB_TT_MODULE) { + given = FALSE; + while (c) { + if (c->iv && iv_get(mrb, c->iv, sym, &v)) { + given = TRUE; + } + c = c->super; + } + if (given) return v; + } + } + mrb_name_error(mrb, sym, "uninitialized class variable %n in %C", sym, cls); /* not reached */ return mrb_nil_value(); } @@ -789,24 +659,43 @@ mrb_mod_cv_set(mrb_state *mrb, struct RClass *c, mrb_sym sym, mrb_value v) struct RClass * cls = c; while (c) { - if (c->iv) { - iv_tbl *t = c->iv; + iv_tbl *t = c->iv; - if (iv_get(mrb, t, sym, NULL)) { - mrb_write_barrier(mrb, (struct RBasic*)c); - iv_put(mrb, t, sym, v); - return; - } + if (iv_get(mrb, t, sym, NULL)) { + mrb_check_frozen(mrb, c); + iv_put(mrb, t, sym, v); + mrb_field_write_barrier_value(mrb, (struct RBasic*)c, v); + return; } c = c->super; } - if (!cls->iv) { - cls->iv = iv_new(mrb); + if (cls && cls->tt == MRB_TT_SCLASS) { + mrb_value klass; + + klass = mrb_obj_iv_get(mrb, (struct RObject*)cls, MRB_SYM(__attached__)); + switch (mrb_type(klass)) { + case MRB_TT_CLASS: + case MRB_TT_MODULE: + case MRB_TT_SCLASS: + c = mrb_class_ptr(klass); + break; + default: + c = cls; + break; + } + } + else{ + c = cls; + } + + mrb_check_frozen(mrb, c); + if (!c->iv) { + c->iv = iv_new(mrb); } - mrb_write_barrier(mrb, (struct RBasic*)cls); - iv_put(mrb, cls->iv, sym, v); + iv_put(mrb, c->iv, sym, v); + mrb_field_write_barrier_value(mrb, (struct RBasic*)c, v); } MRB_API void @@ -815,14 +704,12 @@ mrb_cv_set(mrb_state *mrb, mrb_value mod, mrb_sym sym, mrb_value v) mrb_mod_cv_set(mrb, mrb_class_ptr(mod), sym, v); } -MRB_API mrb_bool +mrb_bool mrb_mod_cv_defined(mrb_state *mrb, struct RClass * c, mrb_sym sym) { while (c) { - if (c->iv) { - iv_tbl *t = c->iv; - if (iv_get(mrb, t, sym, NULL)) return TRUE; - } + iv_tbl *t = c->iv; + if (iv_get(mrb, t, sym, NULL)) return TRUE; c = c->super; } @@ -838,19 +725,29 @@ mrb_cv_defined(mrb_state *mrb, mrb_value mod, mrb_sym sym) mrb_value mrb_vm_cv_get(mrb_state *mrb, mrb_sym sym) { - struct RClass *c = mrb->c->ci->proc->target_class; + struct RClass *c; - if (!c) c = mrb->c->ci->target_class; + const struct RProc *p = mrb->c->ci->proc; + for (;;) { + c = MRB_PROC_TARGET_CLASS(p); + if (c && c->tt != MRB_TT_SCLASS) break; + p = p->upper; + } return mrb_mod_cv_get(mrb, c, sym); } void mrb_vm_cv_set(mrb_state *mrb, mrb_sym sym, mrb_value v) { - struct RClass *c = mrb->c->ci->proc->target_class; + struct RClass *c; + const struct RProc *p = mrb->c->ci->proc; - if (!c) c = mrb->c->ci->target_class; + for (;;) { + c = MRB_PROC_TARGET_CLASS(p); + if (c && c->tt != MRB_TT_SCLASS) break; + p = p->upper; + } mrb_mod_cv_set(mrb, c, sym, v); } @@ -869,77 +766,90 @@ mod_const_check(mrb_state *mrb, mrb_value mod) } static mrb_value -const_get(mrb_state *mrb, struct RClass *base, mrb_sym sym) +const_get(mrb_state *mrb, struct RClass *base, mrb_sym sym, mrb_bool skip) { struct RClass *c = base; mrb_value v; - iv_tbl *t; mrb_bool retry = FALSE; mrb_value name; + if (skip) c = c->super; L_RETRY: while (c) { - if (c->iv) { - t = c->iv; - if (iv_get(mrb, t, sym, &v)) + if (!MRB_FLAG_TEST(c, MRB_FL_CLASS_IS_PREPENDED) && c->iv) { + if (iv_get(mrb, c->iv, sym, &v)) return v; } c = c->super; } - if (!retry && base && base->tt == MRB_TT_MODULE) { + if (!retry && base->tt == MRB_TT_MODULE) { c = mrb->object_class; retry = TRUE; goto L_RETRY; } name = mrb_symbol_value(sym); - return mrb_funcall_argv(mrb, mrb_obj_value(base), mrb_intern_lit(mrb, "const_missing"), 1, &name); + return mrb_funcall_argv(mrb, mrb_obj_value(base), MRB_SYM(const_missing), 1, &name); } MRB_API 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); + return const_get(mrb, mrb_class_ptr(mod), sym, FALSE); } mrb_value mrb_vm_const_get(mrb_state *mrb, mrb_sym sym) { - struct RClass *c = mrb->c->ci->proc->target_class; + struct RClass *c; + struct RClass *c2; + mrb_value v; + const struct RProc *proc = mrb->c->ci->proc; - if (!c) c = mrb->c->ci->target_class; - if (c) { - struct RClass *c2; - mrb_value v; + c = MRB_PROC_TARGET_CLASS(proc); + if (!c) c = mrb->object_class; + if (iv_get(mrb, c->iv, sym, &v)) { + return v; + } + c2 = c; + while (c2 && c2->tt == MRB_TT_SCLASS) { + mrb_value klass; - if (c->iv && iv_get(mrb, c->iv, sym, &v)) { - return v; + if (!iv_get(mrb, c2->iv, MRB_SYM(__attached__), &klass)) { + c2 = NULL; + break; } - c2 = c; - for (;;) { - c2 = mrb_class_outer_module(mrb, c2); - if (!c2) break; - if (c2->iv && iv_get(mrb, c2->iv, sym, &v)) { - return v; - } + c2 = mrb_class_ptr(klass); + } + if (c2 && (c2->tt == MRB_TT_CLASS || c2->tt == MRB_TT_MODULE)) c = c2; + proc = proc->upper; + while (proc) { + c2 = MRB_PROC_TARGET_CLASS(proc); + if (c2 && iv_get(mrb, c2->iv, sym, &v)) { + return v; } + proc = proc->upper; } - return const_get(mrb, c, sym); + return const_get(mrb, c, sym, TRUE); } MRB_API void mrb_const_set(mrb_state *mrb, mrb_value mod, mrb_sym sym, mrb_value v) { mod_const_check(mrb, mod); + if (mrb_type(v) == MRB_TT_CLASS || mrb_type(v) == MRB_TT_MODULE) { + mrb_class_name_class(mrb, mrb_class_ptr(mod), mrb_class_ptr(v), sym); + } mrb_iv_set(mrb, mod, sym, v); } void mrb_vm_const_set(mrb_state *mrb, mrb_sym sym, mrb_value v) { - struct RClass *c = mrb->c->ci->proc->target_class; + struct RClass *c; - if (!c) c = mrb->c->ci->target_class; + c = MRB_PROC_TARGET_CLASS(mrb->c->ci->proc); + if (!c) c = mrb->object_class; mrb_obj_iv_set(mrb, (struct RObject*)c, sym, v); } @@ -951,6 +861,12 @@ mrb_const_remove(mrb_state *mrb, mrb_value mod, mrb_sym sym) } MRB_API void +mrb_define_const_id(mrb_state *mrb, struct RClass *mod, mrb_sym name, mrb_value v) +{ + mrb_obj_iv_set(mrb, (struct RObject*)mod, name, v); +} + +MRB_API 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_cstr(mrb, name), v); @@ -970,9 +886,17 @@ const_i(mrb_state *mrb, mrb_sym sym, mrb_value v, void *p) mrb_int len; ary = *(mrb_value*)p; - s = mrb_sym2name_len(mrb, sym, &len); + s = mrb_sym_name_len(mrb, sym, &len); if (len >= 1 && ISUPPER(s[0])) { - mrb_ary_push(mrb, ary, mrb_symbol_value(sym)); + mrb_int i, alen = RARRAY_LEN(ary); + + for (i=0; i<alen; i++) { + if (mrb_symbol(RARRAY_PTR(ary)[i]) == sym) + break; + } + if (i==alen) { + mrb_ary_push(mrb, ary, mrb_symbol_value(sym)); + } } return 0; } @@ -982,7 +906,7 @@ const_i(mrb_state *mrb, mrb_sym sym, mrb_value v, void *p) * call-seq: * mod.constants -> array * - * Returns an array of all names of contants defined in the receiver. + * Returns an array of all names of constants defined in the receiver. */ mrb_value mrb_mod_constants(mrb_state *mrb, mrb_value mod) @@ -994,9 +918,7 @@ mrb_mod_constants(mrb_state *mrb, mrb_value mod) mrb_get_args(mrb, "|b", &inherit); ary = mrb_ary_new(mrb); while (c) { - if (c->iv) { - iv_foreach(mrb, c->iv, const_i, &ary); - } + iv_foreach(mrb, c->iv, const_i, &ary); if (!inherit) break; c = c->super; if (c == mrb->object_class) break; @@ -1009,9 +931,6 @@ mrb_gv_get(mrb_state *mrb, mrb_sym sym) { mrb_value v; - if (!mrb->globals) { - return mrb_nil_value(); - } if (iv_get(mrb, mrb->globals, sym, &v)) return v; return mrb_nil_value(); @@ -1023,20 +942,15 @@ mrb_gv_set(mrb_state *mrb, mrb_sym sym, mrb_value v) iv_tbl *t; if (!mrb->globals) { - t = mrb->globals = iv_new(mrb); - } - else { - t = mrb->globals; + mrb->globals = iv_new(mrb); } + t = mrb->globals; iv_put(mrb, t, sym, v); } MRB_API void mrb_gv_remove(mrb_state *mrb, mrb_sym sym) { - if (!mrb->globals) { - return; - } iv_del(mrb, mrb->globals, sym, NULL); } @@ -1065,18 +979,8 @@ mrb_f_global_variables(mrb_state *mrb, mrb_value self) { iv_tbl *t = mrb->globals; mrb_value ary = mrb_ary_new(mrb); - size_t i; - char buf[3]; - if (t) { - iv_foreach(mrb, t, gv_i, &ary); - } - 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, 2))); - } + iv_foreach(mrb, t, gv_i, &ary); return ary; } @@ -1085,19 +989,19 @@ mrb_const_defined_0(mrb_state *mrb, mrb_value mod, mrb_sym id, mrb_bool exclude, { struct RClass *klass = mrb_class_ptr(mod); struct RClass *tmp; - mrb_bool mod_retry = 0; + mrb_bool mod_retry = FALSE; tmp = klass; retry: while (tmp) { - if (tmp->iv && iv_get(mrb, tmp->iv, id, NULL)) { + if (iv_get(mrb, tmp->iv, id, NULL)) { return TRUE; } if (!recurse && (klass != mrb->object_class)) break; tmp = tmp->super; } if (!exclude && !mod_retry && (klass->tt == MRB_TT_MODULE)) { - mod_retry = 1; + mod_retry = TRUE; tmp = mrb->object_class; goto retry; } @@ -1140,23 +1044,99 @@ csym_i(mrb_state *mrb, mrb_sym sym, mrb_value v, void *p) return 0; } -mrb_sym -mrb_class_sym(mrb_state *mrb, struct RClass *c, struct RClass *outer) +static mrb_sym +find_class_sym(mrb_state *mrb, struct RClass *outer, struct RClass *c) { - mrb_value name; + struct csym_arg arg; - name = mrb_obj_iv_get(mrb, (struct RObject*)c, mrb_intern_lit(mrb, "__classid__")); - if (mrb_nil_p(name)) { + if (!outer) return 0; + if (outer == c) return 0; + arg.c = c; + arg.sym = 0; + iv_foreach(mrb, outer->iv, csym_i, &arg); + return arg.sym; +} - if (!outer) return 0; - else { - struct csym_arg arg; +static struct RClass* +outer_class(mrb_state *mrb, struct RClass *c) +{ + mrb_value ov; - arg.c = c; - arg.sym = 0; - iv_foreach(mrb, outer->iv, csym_i, &arg); - return arg.sym; - } + ov = mrb_obj_iv_get(mrb, (struct RObject*)c, MRB_SYM(__outer__)); + if (mrb_nil_p(ov)) return NULL; + switch (mrb_type(ov)) { + case MRB_TT_CLASS: + case MRB_TT_MODULE: + return mrb_class_ptr(ov); + default: + break; + } + return NULL; +} + +static mrb_bool +detect_outer_loop(mrb_state *mrb, struct RClass *c) +{ + struct RClass *t = c; /* tortoise */ + struct RClass *h = c; /* hare */ + + for (;;) { + if (h == NULL) return FALSE; + h = outer_class(mrb, h); + if (h == NULL) return FALSE; + h = outer_class(mrb, h); + t = outer_class(mrb, t); + if (t == h) return TRUE; + } +} + +mrb_value +mrb_class_find_path(mrb_state *mrb, struct RClass *c) +{ + struct RClass *outer; + mrb_value path; + mrb_sym name; + const char *str; + mrb_int len; + + if (detect_outer_loop(mrb, c)) return mrb_nil_value(); + outer = outer_class(mrb, c); + if (outer == NULL) return mrb_nil_value(); + name = find_class_sym(mrb, outer, c); + if (name == 0) return mrb_nil_value(); + str = mrb_class_name(mrb, outer); + path = mrb_str_new_capa(mrb, 40); + mrb_str_cat_cstr(mrb, path, str); + mrb_str_cat_cstr(mrb, path, "::"); + + str = mrb_sym_name_len(mrb, name, &len); + mrb_str_cat(mrb, path, str, len); + if (RSTRING_PTR(path)[0] != '#') { + iv_del(mrb, c->iv, MRB_SYM(__outer__), NULL); + iv_put(mrb, c->iv, MRB_SYM(__classname__), path); + mrb_field_write_barrier_value(mrb, (struct RBasic*)c, path); + path = mrb_str_dup(mrb, path); } - return mrb_symbol(name); + return path; +} + +size_t +mrb_obj_iv_tbl_memsize(mrb_value obj) +{ + iv_tbl *t = mrb_obj_ptr(obj)->iv; + if (t == NULL) return 0; + return sizeof(iv_tbl) + t->alloc*sizeof(struct iv_elem); +} + +#define identchar(c) (ISALNUM(c) || (c) == '_' || !ISASCII(c)) + +mrb_bool +mrb_ident_p(const char *s, mrb_int len) +{ + mrb_int i; + + for (i = 0; i < len; i++) { + if (!identchar(s[i])) return FALSE; + } + return TRUE; } |
