Merge pull request #6289 from dearblue/orphan-block
[mruby.git] / src / variable.c
blob2afbfd93e6380bd31de8682ca884a88fcad6844c
1 /*
2 ** variable.c - mruby variables
3 **
4 ** See Copyright Notice in mruby.h
5 */
7 #include <mruby.h>
8 #include <mruby/array.h>
9 #include <mruby/class.h>
10 #include <mruby/proc.h>
11 #include <mruby/string.h>
12 #include <mruby/variable.h>
13 #include <mruby/internal.h>
14 #include <mruby/presym.h>
16 /* Instance variable table structure */
17 typedef struct iv_tbl {
18 int size, alloc;
19 mrb_value *ptr;
20 } iv_tbl;
22 #define IV_EMPTY 0
23 #define IV_DELETED (1UL<<31)
24 #define IV_KEY_P(k) (((k)&~((uint32_t)IV_DELETED))!=0)
26 /* Creates the instance variable table. */
27 static iv_tbl*
28 iv_new(mrb_state *mrb)
30 iv_tbl *t;
32 t = (iv_tbl*)mrb_malloc(mrb, sizeof(iv_tbl));
33 t->size = 0;
34 t->alloc = 0;
35 t->ptr = NULL;
37 return t;
40 static void iv_put(mrb_state *mrb, iv_tbl *t, mrb_sym sym, mrb_value val);
42 static void
43 iv_rehash(mrb_state *mrb, iv_tbl *t)
45 int old_alloc = t->alloc;
46 int new_alloc = old_alloc > 0 ? old_alloc << 1 : 4;
47 mrb_value *old_ptr = t->ptr;
49 t->ptr = (mrb_value*)mrb_calloc(mrb, sizeof(mrb_value)+sizeof(mrb_sym), new_alloc);
50 t->size = 0;
51 t->alloc = new_alloc;
52 if (old_alloc == 0) return;
54 mrb_sym *keys = (mrb_sym*)&old_ptr[old_alloc];
55 mrb_value *vals = old_ptr;
56 for (int i = 0; i < old_alloc; i++) {
57 if (IV_KEY_P(keys[i])) {
58 iv_put(mrb, t, keys[i], vals[i]);
61 mrb_free(mrb, old_ptr);
64 /* Set the value for the symbol in the instance variable table. */
65 static void
66 iv_put(mrb_state *mrb, iv_tbl *t, mrb_sym sym, mrb_value val)
68 int hash, pos, start, dpos = -1;
70 if (t->alloc == 0) {
71 iv_rehash(mrb, t);
74 mrb_sym *keys = (mrb_sym*)&t->ptr[t->alloc];
75 mrb_value *vals = t->ptr;
76 hash = mrb_int_hash_func(mrb, sym);
77 start = pos = hash & (t->alloc-1);
78 for (;;) {
79 mrb_sym key = keys[pos];
80 if (key == sym) {
81 vals[pos] = val;
82 return;
84 else if (key == IV_EMPTY) {
85 t->size++;
86 keys[pos] = sym;
87 vals[pos] = val;
88 return;
90 else if (key == IV_DELETED && dpos < 0) {
91 dpos = pos;
93 pos = (pos+1) & (t->alloc-1);
94 if (pos == start) { /* not found */
95 if (dpos >= 0) {
96 t->size++;
97 keys[dpos] = sym;
98 vals[dpos] = val;
99 return;
101 /* no room */
102 iv_rehash(mrb, t);
103 keys = (mrb_sym*)&t->ptr[t->alloc];
104 vals = t->ptr;
105 start = pos = hash & (t->alloc-1);
110 /* Get a value for a symbol from the instance variable table. */
111 static int
112 iv_get(mrb_state *mrb, iv_tbl *t, mrb_sym sym, mrb_value *vp)
114 int hash, pos, start;
116 if (t == NULL) return FALSE;
117 if (t->alloc == 0) return FALSE;
118 if (t->size == 0) return FALSE;
120 mrb_sym *keys = (mrb_sym*)&t->ptr[t->alloc];
121 mrb_value *vals = t->ptr;
122 hash = mrb_int_hash_func(mrb, sym);
123 start = pos = hash & (t->alloc-1);
124 for (;;) {
125 mrb_sym key = keys[pos];
126 if (key == sym) {
127 if (vp) *vp = vals[pos];
128 return pos+1;
130 else if (key == IV_EMPTY) {
131 return 0;
133 pos = (pos+1) & (t->alloc-1);
134 if (pos == start) { /* not found */
135 return 0;
140 /* Deletes the value for the symbol from the instance variable table. */
141 static mrb_bool
142 iv_del(mrb_state *mrb, iv_tbl *t, mrb_sym sym, mrb_value *vp)
144 int hash, pos, start;
146 if (t == NULL) return FALSE;
147 if (t->alloc == 0) return FALSE;
148 if (t->size == 0) return FALSE;
150 mrb_sym *keys = (mrb_sym*)&t->ptr[t->alloc];
151 mrb_value *vals = t->ptr;
152 hash = mrb_int_hash_func(mrb, sym);
153 start = pos = hash & (t->alloc-1);
154 for (;;) {
155 mrb_sym key = keys[pos];
156 if (key == sym) {
157 if (vp) *vp = vals[pos];
158 t->size--;
159 keys[pos] = IV_DELETED;
160 return TRUE;
162 else if (key == IV_EMPTY) {
163 return FALSE;
165 pos = (pos+1) & (t->alloc-1);
166 if (pos == start) { /* not found */
167 return FALSE;
172 /* Iterates over the instance variable table. */
173 static void
174 iv_foreach(mrb_state *mrb, iv_tbl *t, mrb_iv_foreach_func *func, void *p)
176 if (t == NULL) return;
177 if (t->alloc == 0) return;
178 if (t->size == 0) return;
180 mrb_sym *keys = (mrb_sym*)&t->ptr[t->alloc];
181 mrb_value *vals = t->ptr;
182 for (int i=0; i<t->alloc; i++) {
183 if (IV_KEY_P(keys[i])) {
184 if ((*func)(mrb, keys[i], vals[i], p) != 0) {
185 return;
189 return;
192 /* Get the size of the instance variable table. */
193 /* Size is approximated by the allocated table size. */
194 static size_t
195 iv_size(mrb_state *mrb, iv_tbl *t)
197 if (t == NULL) return 0;
198 return (size_t)t->size;
201 /* Copy the instance variable table. */
202 static iv_tbl*
203 iv_copy(mrb_state *mrb, iv_tbl *t)
205 iv_tbl *t2;
207 if (t == NULL) return NULL;
208 if (t->alloc == 0) return NULL;
209 if (t->size == 0) return NULL;
211 mrb_sym *keys = (mrb_sym*)&t->ptr[t->alloc];
212 mrb_value *vals = t->ptr;
213 t2 = iv_new(mrb);
214 for (int i=0; i<t->alloc; i++) {
215 if (IV_KEY_P(keys[i])) {
216 iv_put(mrb, t2, keys[i], vals[i]);
219 return t2;
222 /* Free memory of the instance variable table. */
223 static void
224 iv_free(mrb_state *mrb, iv_tbl *t)
226 mrb_free(mrb, t->ptr);
227 mrb_free(mrb, t);
230 static int
231 iv_mark_i(mrb_state *mrb, mrb_sym sym, mrb_value v, void *p)
233 mrb_gc_mark_value(mrb, v);
234 return 0;
237 static void
238 mark_tbl(mrb_state *mrb, iv_tbl *t)
240 iv_foreach(mrb, t, iv_mark_i, 0);
243 void
244 mrb_gc_mark_gv(mrb_state *mrb)
246 mark_tbl(mrb, mrb->globals);
249 void
250 mrb_gc_free_gv(mrb_state *mrb)
252 if (mrb->globals)
253 iv_free(mrb, mrb->globals);
256 size_t
257 mrb_gc_mark_iv(mrb_state *mrb, struct RObject *obj)
259 mark_tbl(mrb, obj->iv);
260 return iv_size(mrb, obj->iv);
263 void
264 mrb_gc_free_iv(mrb_state *mrb, struct RObject *obj)
266 if (obj->iv) {
267 iv_free(mrb, obj->iv);
271 mrb_value
272 mrb_vm_special_get(mrb_state *mrb, mrb_sym i)
274 return mrb_fixnum_value(0);
277 void
278 mrb_vm_special_set(mrb_state *mrb, mrb_sym i, mrb_value v)
282 static mrb_bool
283 obj_iv_p(mrb_value obj)
285 switch (mrb_type(obj)) {
286 case MRB_TT_OBJECT:
287 case MRB_TT_CLASS:
288 case MRB_TT_MODULE:
289 case MRB_TT_SCLASS:
290 case MRB_TT_HASH:
291 case MRB_TT_CDATA:
292 case MRB_TT_EXCEPTION:
293 return TRUE;
294 default:
295 return FALSE;
299 static iv_tbl*
300 class_iv_ptr(struct RClass *c)
302 return c->tt == MRB_TT_ICLASS ? c->c->iv : c->iv;
305 MRB_API mrb_value
306 mrb_obj_iv_get(mrb_state *mrb, struct RObject *obj, mrb_sym sym)
308 mrb_value v;
310 if (obj->iv && iv_get(mrb, obj->iv, sym, &v))
311 return v;
312 return mrb_nil_value();
315 MRB_API mrb_value
316 mrb_iv_get(mrb_state *mrb, mrb_value obj, mrb_sym sym)
318 if (obj_iv_p(obj)) {
319 return mrb_obj_iv_get(mrb, mrb_obj_ptr(obj), sym);
321 return mrb_nil_value();
324 static inline mrb_bool
325 namespace_p(enum mrb_vtype tt)
327 return tt == MRB_TT_CLASS || tt == MRB_TT_MODULE ? TRUE : FALSE;
330 static inline void
331 assign_class_name(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v)
333 if (namespace_p(mrb_type(v))) {
334 struct RObject *c = mrb_obj_ptr(v);
335 if (obj != c && ISUPPER(mrb_sym_name_len(mrb, sym, NULL)[0])) {
336 mrb_sym id_classname = MRB_SYM(__classname__);
337 mrb_value o = mrb_obj_iv_get(mrb, c, id_classname);
339 if (mrb_nil_p(o)) {
340 mrb_sym id_outer = MRB_SYM(__outer__);
341 o = mrb_obj_iv_get(mrb, c, id_outer);
343 if (mrb_nil_p(o)) {
344 if ((struct RClass*)obj == mrb->object_class) {
345 mrb_obj_iv_set_force(mrb, c, id_classname, mrb_symbol_value(sym));
347 else {
348 mrb_obj_iv_set_force(mrb, c, id_outer, mrb_obj_value(obj));
356 void
357 mrb_obj_iv_set_force(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v)
359 if (namespace_p(obj->tt)) {
360 assign_class_name(mrb, obj, sym, v);
362 if (!obj->iv) {
363 obj->iv = iv_new(mrb);
365 iv_put(mrb, obj->iv, sym, v);
366 mrb_field_write_barrier_value(mrb, (struct RBasic*)obj, v);
369 MRB_API void
370 mrb_obj_iv_set(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v)
372 mrb_check_frozen(mrb, obj);
373 mrb_obj_iv_set_force(mrb, obj, sym, v);
376 /* Iterates over the instance variable table. */
377 MRB_API void
378 mrb_iv_foreach(mrb_state *mrb, mrb_value obj, mrb_iv_foreach_func *func, void *p)
380 if (!obj_iv_p(obj)) return;
381 iv_foreach(mrb, mrb_obj_ptr(obj)->iv, func, p);
384 MRB_API void
385 mrb_iv_set(mrb_state *mrb, mrb_value obj, mrb_sym sym, mrb_value v)
387 if (obj_iv_p(obj)) {
388 mrb_obj_iv_set(mrb, mrb_obj_ptr(obj), sym, v);
390 else {
391 mrb_raise(mrb, E_ARGUMENT_ERROR, "cannot set instance variable");
395 MRB_API mrb_bool
396 mrb_obj_iv_defined(mrb_state *mrb, struct RObject *obj, mrb_sym sym)
398 iv_tbl *t;
400 t = obj->iv;
401 if (t && iv_get(mrb, t, sym, NULL)) return TRUE;
402 return FALSE;
405 MRB_API mrb_bool
406 mrb_iv_defined(mrb_state *mrb, mrb_value obj, mrb_sym sym)
408 if (!obj_iv_p(obj)) return FALSE;
409 return mrb_obj_iv_defined(mrb, mrb_obj_ptr(obj), sym);
412 MRB_API mrb_bool
413 mrb_iv_name_sym_p(mrb_state *mrb, mrb_sym iv_name)
415 const char *s;
416 mrb_int len;
418 s = mrb_sym_name_len(mrb, iv_name, &len);
419 if (len < 2) return FALSE;
420 if (s[0] != '@') return FALSE;
421 if (ISDIGIT(s[1])) return FALSE;
422 return mrb_ident_p(s+1, len-1);
425 MRB_API void
426 mrb_iv_name_sym_check(mrb_state *mrb, mrb_sym iv_name)
428 if (!mrb_iv_name_sym_p(mrb, iv_name)) {
429 mrb_name_error(mrb, iv_name, "'%n' is not allowed as an instance variable name", iv_name);
433 MRB_API void
434 mrb_iv_copy(mrb_state *mrb, mrb_value dest, mrb_value src)
436 struct RObject *d = mrb_obj_ptr(dest);
437 struct RObject *s = mrb_obj_ptr(src);
439 if (d->iv) {
440 iv_free(mrb, d->iv);
441 d->iv = 0;
443 if (s->iv) {
444 mrb_write_barrier(mrb, (struct RBasic*)d);
445 d->iv = iv_copy(mrb, s->iv);
449 static int
450 inspect_i(mrb_state *mrb, mrb_sym sym, mrb_value v, void *p)
452 mrb_value str = *(mrb_value*)p;
453 const char *s;
454 mrb_int len;
455 mrb_value ins;
456 char *sp = RSTRING_PTR(str);
458 /* need not to show internal data */
459 if (sp[0] == '-') { /* first element */
460 sp[0] = '#';
461 mrb_str_cat_lit(mrb, str, " ");
463 else {
464 mrb_str_cat_lit(mrb, str, ", ");
466 s = mrb_sym_name_len(mrb, sym, &len);
467 mrb_str_cat(mrb, str, s, len);
468 mrb_str_cat_lit(mrb, str, "=");
469 ins = mrb_inspect(mrb, v);
470 mrb_str_cat_str(mrb, str, ins);
471 return 0;
474 mrb_value
475 mrb_obj_iv_inspect(mrb_state *mrb, struct RObject *obj)
477 iv_tbl *t = obj->iv;
478 size_t len = iv_size(mrb, t);
480 if (len > 0) {
481 const char *cn = mrb_obj_classname(mrb, mrb_obj_value(obj));
482 mrb_value str = mrb_str_new_capa(mrb, 30);
484 mrb_str_cat_lit(mrb, str, "-<");
485 mrb_str_cat_cstr(mrb, str, cn);
486 mrb_str_cat_lit(mrb, str, ":");
487 mrb_str_cat_str(mrb, str, mrb_ptr_to_str(mrb, obj));
489 if (mrb_inspect_recursive_p(mrb, mrb_obj_value(obj))) {
490 mrb_str_cat_lit(mrb, str, " ...>");
491 return str;
493 iv_foreach(mrb, t, inspect_i, &str);
494 mrb_str_cat_lit(mrb, str, ">");
495 return str;
497 return mrb_any_to_s(mrb, mrb_obj_value(obj));
500 MRB_API mrb_value
501 mrb_iv_remove(mrb_state *mrb, mrb_value obj, mrb_sym sym)
503 if (obj_iv_p(obj)) {
504 struct RObject *o = mrb_obj_ptr(obj);
505 iv_tbl *t = o->iv;
506 mrb_value val;
508 mrb_check_frozen(mrb, o);
509 if (iv_del(mrb, t, sym, &val)) {
510 return val;
513 return mrb_undef_value();
516 static int
517 iv_i(mrb_state *mrb, mrb_sym sym, mrb_value v, void *p)
519 mrb_value ary;
520 const char* s;
521 mrb_int len;
523 ary = *(mrb_value*)p;
524 s = mrb_sym_name_len(mrb, sym, &len);
525 if (len > 1 && s[0] == '@' && s[1] != '@') {
526 mrb_ary_push(mrb, ary, mrb_symbol_value(sym));
528 return 0;
531 /* 15.3.1.3.23 */
533 * call-seq:
534 * obj.instance_variables -> array
536 * Returns an array of instance variable names for the receiver. Note
537 * that simply defining an accessor does not create the corresponding
538 * instance variable.
540 * class Fred
541 * attr_accessor :a1
542 * def initialize
543 * @iv = 3
544 * end
545 * end
546 * Fred.new.instance_variables #=> [:@iv]
548 mrb_value
549 mrb_obj_instance_variables(mrb_state *mrb, mrb_value self)
551 mrb_value ary;
553 ary = mrb_ary_new(mrb);
554 if (obj_iv_p(self)) {
555 iv_foreach(mrb, mrb_obj_ptr(self)->iv, iv_i, &ary);
557 return ary;
560 static int
561 cv_i(mrb_state *mrb, mrb_sym sym, mrb_value v, void *p)
563 mrb_value ary;
564 const char* s;
565 mrb_int len;
567 ary = *(mrb_value*)p;
568 s = mrb_sym_name_len(mrb, sym, &len);
569 if (len > 2 && s[0] == '@' && s[1] == '@') {
570 mrb_ary_push(mrb, ary, mrb_symbol_value(sym));
572 return 0;
575 /* 15.2.2.4.19 */
577 * call-seq:
578 * mod.class_variables(inherit=true) -> array
580 * Returns an array of the names of class variables in <i>mod</i>.
582 * class One
583 * @@var1 = 1
584 * end
585 * class Two < One
586 * @@var2 = 2
587 * end
588 * One.class_variables #=> [:@@var1]
589 * Two.class_variables #=> [:@@var2]
591 mrb_value
592 mrb_mod_class_variables(mrb_state *mrb, mrb_value mod)
594 mrb_value ary;
595 struct RClass *c;
596 mrb_bool inherit = TRUE;
598 mrb_get_args(mrb, "|b", &inherit);
599 ary = mrb_ary_new(mrb);
600 c = mrb_class_ptr(mod);
601 while (c) {
602 iv_foreach(mrb, class_iv_ptr(c), cv_i, &ary);
603 if (!inherit) break;
604 c = c->super;
606 return ary;
609 mrb_value
610 mrb_mod_cv_get(mrb_state *mrb, struct RClass *c, mrb_sym sym)
612 struct RClass * cls = c;
613 mrb_value v;
614 int given = FALSE;
616 while (c) {
617 if (iv_get(mrb, class_iv_ptr(c), sym, &v)) {
618 given = TRUE;
620 c = c->super;
622 if (given) return v;
623 if (cls && cls->tt == MRB_TT_SCLASS) {
624 mrb_value klass;
626 klass = mrb_obj_iv_get(mrb, (struct RObject*)cls, MRB_SYM(__attached__));
627 c = mrb_class_ptr(klass);
628 if (c->tt == MRB_TT_CLASS || c->tt == MRB_TT_MODULE) {
629 given = FALSE;
630 while (c) {
631 if (iv_get(mrb, class_iv_ptr(c), sym, &v)) {
632 given = TRUE;
634 c = c->super;
636 if (given) return v;
639 mrb_name_error(mrb, sym, "uninitialized class variable %n in %C", sym, cls);
640 /* not reached */
641 return mrb_nil_value();
644 MRB_API mrb_value
645 mrb_cv_get(mrb_state *mrb, mrb_value mod, mrb_sym sym)
647 return mrb_mod_cv_get(mrb, mrb_class_ptr(mod), sym);
650 MRB_API void
651 mrb_mod_cv_set(mrb_state *mrb, struct RClass *c, mrb_sym sym, mrb_value v)
653 struct RClass * cls = c;
655 while (c) {
656 iv_tbl *t = class_iv_ptr(c);
657 int pos = iv_get(mrb, t, sym, NULL);
659 if (pos) {
660 mrb_check_frozen(mrb, c);
661 t->ptr[pos-1] = v; /* iv_get returns pos+1 to put */
662 mrb_field_write_barrier_value(mrb, (struct RBasic*)c, v);
663 return;
665 c = c->super;
668 if (cls && cls->tt == MRB_TT_SCLASS) {
669 mrb_value klass;
671 klass = mrb_obj_iv_get(mrb, (struct RObject*)cls, MRB_SYM(__attached__));
672 switch (mrb_type(klass)) {
673 case MRB_TT_CLASS:
674 case MRB_TT_MODULE:
675 case MRB_TT_SCLASS:
676 c = mrb_class_ptr(klass);
677 break;
678 default:
679 c = cls;
680 break;
683 else if (cls && cls->tt == MRB_TT_ICLASS) {
684 c = cls->c;
686 else {
687 c = cls;
690 mrb_check_frozen(mrb, c);
691 if (!c->iv) {
692 c->iv = iv_new(mrb);
695 iv_put(mrb, c->iv, sym, v);
696 mrb_field_write_barrier_value(mrb, (struct RBasic*)c, v);
699 MRB_API void
700 mrb_cv_set(mrb_state *mrb, mrb_value mod, mrb_sym sym, mrb_value v)
702 mrb_mod_cv_set(mrb, mrb_class_ptr(mod), sym, v);
705 mrb_bool
706 mrb_mod_cv_defined(mrb_state *mrb, struct RClass * c, mrb_sym sym)
708 while (c) {
709 iv_tbl *t = class_iv_ptr(c);
710 if (iv_get(mrb, t, sym, NULL)) return TRUE;
711 c = c->super;
714 return FALSE;
717 MRB_API mrb_bool
718 mrb_cv_defined(mrb_state *mrb, mrb_value mod, mrb_sym sym)
720 return mrb_mod_cv_defined(mrb, mrb_class_ptr(mod), sym);
723 mrb_value
724 mrb_vm_cv_get(mrb_state *mrb, mrb_sym sym)
726 struct RClass *c;
728 const struct RProc *p = mrb->c->ci->proc;
730 for (;;) {
731 c = MRB_PROC_TARGET_CLASS(p);
732 if (c && c->tt != MRB_TT_SCLASS) break;
733 p = p->upper;
735 return mrb_mod_cv_get(mrb, c, sym);
738 void
739 mrb_vm_cv_set(mrb_state *mrb, mrb_sym sym, mrb_value v)
741 struct RClass *c;
742 const struct RProc *p = mrb->c->ci->proc;
744 for (;;) {
745 c = MRB_PROC_TARGET_CLASS(p);
746 if (c && c->tt != MRB_TT_SCLASS) break;
747 p = p->upper;
749 mrb_mod_cv_set(mrb, c, sym, v);
752 static void
753 mod_const_check(mrb_state *mrb, mrb_value mod)
755 switch (mrb_type(mod)) {
756 case MRB_TT_CLASS:
757 case MRB_TT_MODULE:
758 case MRB_TT_SCLASS:
759 break;
760 default:
761 mrb_raise(mrb, E_TYPE_ERROR, "constant look-up for non class/module");
762 break;
766 static mrb_value
767 const_get(mrb_state *mrb, struct RClass *base, mrb_sym sym, mrb_bool skip)
769 struct RClass *c = base;
770 mrb_value v;
771 mrb_bool retry = FALSE;
773 /* if skip then skip the current class (already searched) */
774 if (skip) c = c->super;
775 L_RETRY:
776 while (c) {
777 if (!MRB_FLAG_TEST(c, MRB_FL_CLASS_IS_PREPENDED) && iv_get(mrb, class_iv_ptr(c), sym, &v)) {
778 return v;
780 c = c->super;
781 if (!skip && c == mrb->object_class) break;
783 if (!retry && base->tt == MRB_TT_MODULE && skip) {
784 c = mrb->object_class;
785 retry = TRUE;
786 goto L_RETRY;
788 mrb_value mod = mrb_obj_value(base);
789 if (mrb_func_basic_p(mrb, mod, MRB_SYM(const_missing), mrb_mod_const_missing)) {
790 return mrb_const_missing(mrb, mod, sym);
792 mrb_value name = mrb_symbol_value(sym);
793 return mrb_funcall_argv(mrb, mod, MRB_SYM(const_missing), 1, &name);
796 MRB_API mrb_value
797 mrb_const_get(mrb_state *mrb, mrb_value mod, mrb_sym sym)
799 mod_const_check(mrb, mod);
800 return const_get(mrb, mrb_class_ptr(mod), sym, FALSE);
803 mrb_value
804 mrb_vm_const_get(mrb_state *mrb, mrb_sym sym)
806 struct RClass *c;
807 struct RClass *c2;
808 mrb_value v;
809 const struct RProc *proc = mrb->c->ci->proc;
811 c = MRB_PROC_TARGET_CLASS(proc);
812 if (!c) c = mrb->object_class;
813 if (iv_get(mrb, class_iv_ptr(c), sym, &v)) {
814 return v;
816 c2 = c;
817 while (c2 && c2->tt == MRB_TT_SCLASS) {
818 mrb_value klass;
820 if (!iv_get(mrb, class_iv_ptr(c2), MRB_SYM(__attached__), &klass)) {
821 c2 = NULL;
822 break;
824 c2 = mrb_class_ptr(klass);
826 if (c2 && (c2->tt == MRB_TT_CLASS || c2->tt == MRB_TT_MODULE)) c = c2;
827 proc = proc->upper;
828 while (proc) {
829 c2 = MRB_PROC_TARGET_CLASS(proc);
830 if (!c2) c2 = mrb->object_class;
831 if (c2 && iv_get(mrb, class_iv_ptr(c2), sym, &v)) {
832 return v;
834 proc = proc->upper;
836 return const_get(mrb, c, sym, TRUE);
839 MRB_API void
840 mrb_const_set(mrb_state *mrb, mrb_value mod, mrb_sym sym, mrb_value v)
842 mod_const_check(mrb, mod);
843 if (mrb_type(v) == MRB_TT_CLASS || mrb_type(v) == MRB_TT_MODULE) {
844 mrb_class_name_class(mrb, mrb_class_ptr(mod), mrb_class_ptr(v), sym);
846 mrb_iv_set(mrb, mod, sym, v);
849 void
850 mrb_vm_const_set(mrb_state *mrb, mrb_sym sym, mrb_value v)
852 struct RClass *c;
854 c = MRB_PROC_TARGET_CLASS(mrb->c->ci->proc);
855 if (!c) c = mrb->object_class;
856 mrb_obj_iv_set(mrb, (struct RObject*)c, sym, v);
859 MRB_API void
860 mrb_const_remove(mrb_state *mrb, mrb_value mod, mrb_sym sym)
862 mod_const_check(mrb, mod);
863 mrb_iv_remove(mrb, mod, sym);
866 MRB_API void
867 mrb_define_const_id(mrb_state *mrb, struct RClass *mod, mrb_sym name, mrb_value v)
869 mrb_obj_iv_set(mrb, (struct RObject*)mod, name, v);
872 MRB_API void
873 mrb_define_const(mrb_state *mrb, struct RClass *mod, const char *name, mrb_value v)
875 mrb_obj_iv_set(mrb, (struct RObject*)mod, mrb_intern_cstr(mrb, name), v);
878 MRB_API void
879 mrb_define_global_const(mrb_state *mrb, const char *name, mrb_value val)
881 mrb_define_const(mrb, mrb->object_class, name, val);
884 static int
885 const_i(mrb_state *mrb, mrb_sym sym, mrb_value v, void *p)
887 mrb_value ary;
888 const char* s;
889 mrb_int len;
891 ary = *(mrb_value*)p;
892 s = mrb_sym_name_len(mrb, sym, &len);
893 if (len >= 1 && ISUPPER(s[0])) {
894 mrb_int i, alen = RARRAY_LEN(ary);
896 for (i=0; i<alen; i++) {
897 if (mrb_symbol(RARRAY_PTR(ary)[i]) == sym)
898 break;
900 if (i==alen) {
901 mrb_ary_push(mrb, ary, mrb_symbol_value(sym));
904 return 0;
907 /* 15.2.2.4.24 */
909 * call-seq:
910 * mod.constants -> array
912 * Returns an array of all names of constants defined in the receiver.
914 mrb_value
915 mrb_mod_constants(mrb_state *mrb, mrb_value mod)
917 mrb_value ary;
918 mrb_bool inherit = TRUE;
919 struct RClass *c = mrb_class_ptr(mod);
921 mrb_get_args(mrb, "|b", &inherit);
922 ary = mrb_ary_new(mrb);
923 while (c) {
924 iv_foreach(mrb, class_iv_ptr(c), const_i, &ary);
925 if (!inherit) break;
926 c = c->super;
927 if (c == mrb->object_class) break;
929 return ary;
932 MRB_API mrb_value
933 mrb_gv_get(mrb_state *mrb, mrb_sym sym)
935 mrb_value v;
937 if (iv_get(mrb, mrb->globals, sym, &v))
938 return v;
939 return mrb_nil_value();
942 MRB_API void
943 mrb_gv_set(mrb_state *mrb, mrb_sym sym, mrb_value v)
945 iv_tbl *t;
947 if (!mrb->globals) {
948 mrb->globals = iv_new(mrb);
950 t = mrb->globals;
951 iv_put(mrb, t, sym, v);
954 MRB_API void
955 mrb_gv_remove(mrb_state *mrb, mrb_sym sym)
957 iv_del(mrb, mrb->globals, sym, NULL);
960 static int
961 gv_i(mrb_state *mrb, mrb_sym sym, mrb_value v, void *p)
963 mrb_value ary;
965 ary = *(mrb_value*)p;
966 mrb_ary_push(mrb, ary, mrb_symbol_value(sym));
967 return 0;
970 /* 15.3.1.2.4 */
971 /* 15.3.1.3.14 */
973 * call-seq:
974 * global_variables -> array
976 * Returns an array of the names of global variables.
978 * global_variables.grep /std/ #=> [:$stdin, :$stdout, :$stderr]
980 mrb_value
981 mrb_f_global_variables(mrb_state *mrb, mrb_value self)
983 iv_tbl *t = mrb->globals;
984 mrb_value ary = mrb_ary_new(mrb);
986 iv_foreach(mrb, t, gv_i, &ary);
987 return ary;
990 static mrb_bool
991 const_defined_0(mrb_state *mrb, mrb_value mod, mrb_sym id, mrb_bool exclude, mrb_bool recurse)
993 struct RClass *klass = mrb_class_ptr(mod);
994 struct RClass *tmp;
995 mrb_bool mod_retry = FALSE;
997 tmp = klass;
998 retry:
999 while (tmp) {
1000 if (iv_get(mrb, class_iv_ptr(tmp), id, NULL)) {
1001 return TRUE;
1003 if (!recurse && (klass != mrb->object_class)) break;
1004 tmp = tmp->super;
1006 if (!exclude && !mod_retry && (klass->tt == MRB_TT_MODULE)) {
1007 mod_retry = TRUE;
1008 tmp = mrb->object_class;
1009 goto retry;
1011 return FALSE;
1014 MRB_API mrb_bool
1015 mrb_const_defined(mrb_state *mrb, mrb_value mod, mrb_sym id)
1017 return const_defined_0(mrb, mod, id, TRUE, TRUE);
1020 MRB_API mrb_bool
1021 mrb_const_defined_at(mrb_state *mrb, mrb_value mod, mrb_sym id)
1023 return const_defined_0(mrb, mod, id, TRUE, FALSE);
1026 MRB_API mrb_value
1027 mrb_attr_get(mrb_state *mrb, mrb_value obj, mrb_sym id)
1029 return mrb_iv_get(mrb, obj, id);
1032 struct csym_arg {
1033 struct RClass *c;
1034 mrb_sym sym;
1037 static int
1038 csym_i(mrb_state *mrb, mrb_sym sym, mrb_value v, void *p)
1040 struct csym_arg *a = (struct csym_arg*)p;
1041 struct RClass *c = a->c;
1043 if (mrb_type(v) == c->tt && mrb_class_ptr(v) == c) {
1044 a->sym = sym;
1045 return 1; /* stop iteration */
1047 return 0;
1050 static mrb_sym
1051 find_class_sym(mrb_state *mrb, struct RClass *outer, struct RClass *c)
1053 struct csym_arg arg;
1055 if (!outer) return 0;
1056 if (outer == c) return 0;
1057 arg.c = c;
1058 arg.sym = 0;
1059 iv_foreach(mrb, class_iv_ptr(outer), csym_i, &arg);
1060 return arg.sym;
1063 static struct RClass*
1064 outer_class(mrb_state *mrb, struct RClass *c)
1066 mrb_value ov;
1068 ov = mrb_obj_iv_get(mrb, (struct RObject*)c, MRB_SYM(__outer__));
1069 if (mrb_nil_p(ov)) return NULL;
1070 switch (mrb_type(ov)) {
1071 case MRB_TT_CLASS:
1072 case MRB_TT_MODULE:
1073 return mrb_class_ptr(ov);
1074 default:
1075 break;
1077 return NULL;
1080 static mrb_bool
1081 detect_outer_loop(mrb_state *mrb, struct RClass *c)
1083 struct RClass *t = c; /* tortoise */
1084 struct RClass *h = c; /* hare */
1086 for (;;) {
1087 if (h == NULL) return FALSE;
1088 h = outer_class(mrb, h);
1089 if (h == NULL) return FALSE;
1090 h = outer_class(mrb, h);
1091 t = outer_class(mrb, t);
1092 if (t == h) return TRUE;
1096 mrb_value
1097 mrb_class_find_path(mrb_state *mrb, struct RClass *c)
1099 struct RClass *outer;
1100 mrb_value path;
1101 mrb_sym name;
1102 const char *str;
1103 mrb_int len;
1105 if (detect_outer_loop(mrb, c)) return mrb_nil_value();
1106 outer = outer_class(mrb, c);
1107 if (outer == NULL) return mrb_nil_value();
1108 name = find_class_sym(mrb, outer, c);
1109 if (name == 0) return mrb_nil_value();
1110 path = mrb_str_new_capa(mrb, 40);
1111 str = mrb_class_name(mrb, outer);
1112 mrb_str_cat_cstr(mrb, path, str);
1113 mrb_str_cat_cstr(mrb, path, "::");
1115 str = mrb_sym_name_len(mrb, name, &len);
1116 mrb_str_cat(mrb, path, str, len);
1117 if (RSTRING_PTR(path)[0] != '#') {
1118 iv_del(mrb, c->iv, MRB_SYM(__outer__), NULL);
1119 iv_put(mrb, c->iv, MRB_SYM(__classname__), path);
1120 mrb_field_write_barrier_value(mrb, (struct RBasic*)c, path);
1121 path = mrb_str_dup(mrb, path);
1123 return path;
1126 size_t
1127 mrb_obj_iv_tbl_memsize(mrb_value obj)
1129 iv_tbl *t = mrb_obj_ptr(obj)->iv;
1130 if (t == NULL) return 0;
1131 return sizeof(iv_tbl) + t->alloc*(sizeof(mrb_value)+sizeof(mrb_sym));
1134 #define identchar(c) (ISALNUM(c) || (c) == '_' || !ISASCII(c))
1136 mrb_bool
1137 mrb_ident_p(const char *s, mrb_int len)
1139 for (mrb_int i = 0; i < len; i++) {
1140 if (!identchar(s[i])) return FALSE;
1142 return TRUE;