source: EcnlProtoTool/trunk/mruby-1.2.0/src/variable.c@ 321

Last change on this file since 321 was 321, checked in by coas-nagasima, 7 years ago

文字コードを設定

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-csrc;charset=UTF-8
File size: 22.8 KB
Line 
1/*
2** variable.c - mruby variables
3**
4** See Copyright Notice in mruby.h
5*/
6
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
13typedef int (iv_foreach_func)(mrb_state*,mrb_sym,mrb_value,void*);
14
15#ifdef MRB_USE_IV_SEGLIST
16
17#ifndef MRB_SEGMENT_SIZE
18#define MRB_SEGMENT_SIZE 4
19#endif
20
21typedef struct segment {
22 mrb_sym key[MRB_SEGMENT_SIZE];
23 mrb_value val[MRB_SEGMENT_SIZE];
24 struct segment *next;
25} segment;
26
27/* Instance variable table structure */
28typedef struct iv_tbl {
29 segment *rootseg;
30 size_t size;
31 size_t last_len;
32} iv_tbl;
33
34/*
35 * Creates the instance variable table.
36 *
37 * Parameters
38 * mrb
39 * Returns
40 * the instance variable table.
41 */
42static iv_tbl*
43iv_new(mrb_state *mrb)
44{
45 iv_tbl *t;
46
47 t = mrb_malloc(mrb, sizeof(iv_tbl));
48 t->size = 0;
49 t->rootseg = NULL;
50 t->last_len = 0;
51
52 return t;
53}
54
55/*
56 * Set the value for the symbol in the instance variable table.
57 *
58 * Parameters
59 * mrb
60 * t the instance variable table to be set in.
61 * sym the symbol to be used as the key.
62 * val the value to be set.
63 */
64static void
65iv_put(mrb_state *mrb, iv_tbl *t, mrb_sym sym, mrb_value val)
66{
67 segment *seg = t->rootseg;
68 segment *prev = NULL;
69 segment *matched_seg = NULL;
70 size_t matched_idx = 0;
71 size_t i;
72
73 while (seg) {
74 for (i=0; i<MRB_SEGMENT_SIZE; i++) {
75 mrb_sym key = seg->key[i];
76 /* Found room in last segment after last_len */
77 if (!seg->next && i >= t->last_len) {
78 seg->key[i] = sym;
79 seg->val[i] = val;
80 t->last_len = i+1;
81 t->size++;
82 return;
83 }
84 if (!matched_seg && key == 0) {
85 matched_seg = seg;
86 matched_idx = i;
87 }
88 else if (key == sym) {
89 seg->val[i] = val;
90 return;
91 }
92 }
93 prev = seg;
94 seg = seg->next;
95 }
96
97 /* Not found */
98 t->size++;
99 if (matched_seg) {
100 matched_seg->key[matched_idx] = sym;
101 matched_seg->val[matched_idx] = val;
102 return;
103 }
104
105 seg = mrb_malloc(mrb, sizeof(segment));
106 if (!seg) return;
107 seg->next = NULL;
108 seg->key[0] = sym;
109 seg->val[0] = val;
110 t->last_len = 1;
111 if (prev) {
112 prev->next = seg;
113 }
114 else {
115 t->rootseg = seg;
116 }
117}
118
119/*
120 * Get a value for a symbol from the instance variable table.
121 *
122 * Parameters
123 * mrb
124 * t the variable table to be searched.
125 * sym the symbol to be used as the key.
126 * vp the value pointer. Receives the value if the specified symbol is
127 * contained in the instance variable table.
128 * Returns
129 * true if the specified symbol is contained in the instance variable table.
130 */
131static mrb_bool
132iv_get(mrb_state *mrb, iv_tbl *t, mrb_sym sym, mrb_value *vp)
133{
134 segment *seg;
135 size_t i;
136
137 seg = t->rootseg;
138 while (seg) {
139 for (i=0; i<MRB_SEGMENT_SIZE; i++) {
140 mrb_sym key = seg->key[i];
141
142 if (!seg->next && i >= t->last_len) {
143 return FALSE;
144 }
145 if (key == sym) {
146 if (vp) *vp = seg->val[i];
147 return TRUE;
148 }
149 }
150 seg = seg->next;
151 }
152 return FALSE;
153}
154
155/*
156 * Deletes the value for the symbol from the instance variable table.
157 *
158 * Parameters
159 * t the variable table to be searched.
160 * sym the symbol to be used as the key.
161 * vp the value pointer. Receive the deleted value if the symbol is
162 * contained in the instance variable table.
163 * Returns
164 * true if the specified symbol is contained in the instance variable table.
165 */
166static mrb_bool
167iv_del(mrb_state *mrb, iv_tbl *t, mrb_sym sym, mrb_value *vp)
168{
169 segment *seg;
170 size_t i;
171
172 seg = t->rootseg;
173 while (seg) {
174 for (i=0; i<MRB_SEGMENT_SIZE; i++) {
175 mrb_sym key = seg->key[i];
176
177 if (!seg->next && i >= t->last_len) {
178 return FALSE;
179 }
180 if (key == sym) {
181 t->size--;
182 seg->key[i] = 0;
183 if (vp) *vp = seg->val[i];
184 return TRUE;
185 }
186 }
187 seg = seg->next;
188 }
189 return FALSE;
190}
191
192static mrb_bool
193iv_foreach(mrb_state *mrb, iv_tbl *t, iv_foreach_func *func, void *p)
194{
195 segment *seg;
196 size_t i;
197 int n;
198
199 seg = t->rootseg;
200 while (seg) {
201 for (i=0; i<MRB_SEGMENT_SIZE; i++) {
202 mrb_sym key = seg->key[i];
203
204 /* no value in last segment after last_len */
205 if (!seg->next && i >= t->last_len) {
206 return FALSE;
207 }
208 if (key != 0) {
209 n =(*func)(mrb, key, seg->val[i], p);
210 if (n > 0) return FALSE;
211 if (n < 0) {
212 t->size--;
213 seg->key[i] = 0;
214 }
215 }
216 }
217 seg = seg->next;
218 }
219 return TRUE;
220}
221
222static size_t
223iv_size(mrb_state *mrb, iv_tbl *t)
224{
225 segment *seg;
226 size_t size = 0;
227
228 if (!t) return 0;
229 if (t->size > 0) return t->size;
230 seg = t->rootseg;
231 while (seg) {
232 if (seg->next == NULL) {
233 size += t->last_len;
234 return size;
235 }
236 seg = seg->next;
237 size += MRB_SEGMENT_SIZE;
238 }
239 /* empty iv_tbl */
240 return 0;
241}
242
243static iv_tbl*
244iv_copy(mrb_state *mrb, iv_tbl *t)
245{
246 segment *seg;
247 iv_tbl *t2;
248
249 size_t i;
250
251 seg = t->rootseg;
252 t2 = iv_new(mrb);
253
254 while (seg != NULL) {
255 for (i=0; i<MRB_SEGMENT_SIZE; i++) {
256 mrb_sym key = seg->key[i];
257 mrb_value val = seg->val[i];
258
259 if ((seg->next == NULL) && (i >= t->last_len)) {
260 return t2;
261 }
262 iv_put(mrb, t2, key, val);
263 }
264 seg = seg->next;
265 }
266 return t2;
267}
268
269static void
270iv_free(mrb_state *mrb, iv_tbl *t)
271{
272 segment *seg;
273
274 seg = t->rootseg;
275 while (seg) {
276 segment *p = seg;
277 seg = seg->next;
278 mrb_free(mrb, p);
279 }
280 mrb_free(mrb, t);
281}
282
283#else
284
285#include "mruby/khash.h"
286
287#ifndef MRB_IVHASH_INIT_SIZE
288#define MRB_IVHASH_INIT_SIZE 8
289#endif
290
291KHASH_DECLARE(iv, mrb_sym, mrb_value, TRUE)
292KHASH_DEFINE(iv, mrb_sym, mrb_value, TRUE, kh_int_hash_func, kh_int_hash_equal)
293
294typedef struct iv_tbl {
295 khash_t(iv) h;
296} iv_tbl;
297
298static iv_tbl*
299iv_new(mrb_state *mrb)
300{
301 return (iv_tbl*)kh_init_size(iv, mrb, MRB_IVHASH_INIT_SIZE);
302}
303
304static void
305iv_put(mrb_state *mrb, iv_tbl *t, mrb_sym sym, mrb_value val)
306{
307 khash_t(iv) *h = &t->h;
308 khiter_t k;
309
310 k = kh_put(iv, mrb, h, sym);
311 kh_value(h, k) = val;
312}
313
314static mrb_bool
315iv_get(mrb_state *mrb, iv_tbl *t, mrb_sym sym, mrb_value *vp)
316{
317 khash_t(iv) *h = &t->h;
318 khiter_t k;
319
320 k = kh_get(iv, mrb, h, sym);
321 if (k != kh_end(h)) {
322 if (vp) *vp = kh_value(h, k);
323 return TRUE;
324 }
325 return FALSE;
326}
327
328static mrb_bool
329iv_del(mrb_state *mrb, iv_tbl *t, mrb_sym sym, mrb_value *vp)
330{
331 khash_t(iv) *h = &t->h;
332 khiter_t k;
333
334 if (h) {
335 k = kh_get(iv, mrb, h, sym);
336 if (k != kh_end(h)) {
337 mrb_value val = kh_value(h, k);
338 kh_del(iv, mrb, h, k);
339 if (vp) *vp = val;
340 return TRUE;
341 }
342 }
343 return FALSE;
344}
345
346static mrb_bool
347iv_foreach(mrb_state *mrb, iv_tbl *t, iv_foreach_func *func, void *p)
348{
349 khash_t(iv) *h = &t->h;
350 khiter_t k;
351 int n;
352
353 if (h) {
354 for (k = kh_begin(h); k != kh_end(h); k++) {
355 if (kh_exist(h, k)) {
356 n = (*func)(mrb, kh_key(h, k), kh_value(h, k), p);
357 if (n > 0) return FALSE;
358 if (n < 0) {
359 kh_del(iv, mrb, h, k);
360 }
361 }
362 }
363 }
364 return TRUE;
365}
366
367static size_t
368iv_size(mrb_state *mrb, iv_tbl *t)
369{
370 khash_t(iv) *h;
371
372 if (t && (h = &t->h)) {
373 return kh_size(h);
374 }
375 return 0;
376}
377
378static iv_tbl*
379iv_copy(mrb_state *mrb, iv_tbl *t)
380{
381 return (iv_tbl*)kh_copy(iv, mrb, &t->h);
382}
383
384static void
385iv_free(mrb_state *mrb, iv_tbl *t)
386{
387 kh_destroy(iv, mrb, &t->h);
388}
389
390#endif
391
392static int
393iv_mark_i(mrb_state *mrb, mrb_sym sym, mrb_value v, void *p)
394{
395 mrb_gc_mark_value(mrb, v);
396 return 0;
397}
398
399static void
400mark_tbl(mrb_state *mrb, iv_tbl *t)
401{
402 if (t) {
403 iv_foreach(mrb, t, iv_mark_i, 0);
404 }
405}
406
407void
408mrb_gc_mark_gv(mrb_state *mrb)
409{
410 mark_tbl(mrb, mrb->globals);
411}
412
413void
414mrb_gc_free_gv(mrb_state *mrb)
415{
416 if (mrb->globals)
417 iv_free(mrb, mrb->globals);
418}
419
420void
421mrb_gc_mark_iv(mrb_state *mrb, struct RObject *obj)
422{
423 mark_tbl(mrb, obj->iv);
424}
425
426size_t
427mrb_gc_mark_iv_size(mrb_state *mrb, struct RObject *obj)
428{
429 return iv_size(mrb, obj->iv);
430}
431
432void
433mrb_gc_free_iv(mrb_state *mrb, struct RObject *obj)
434{
435 if (obj->iv) {
436 iv_free(mrb, obj->iv);
437 }
438}
439
440mrb_value
441mrb_vm_special_get(mrb_state *mrb, mrb_sym i)
442{
443 return mrb_fixnum_value(0);
444}
445
446void
447mrb_vm_special_set(mrb_state *mrb, mrb_sym i, mrb_value v)
448{
449}
450
451static mrb_bool
452obj_iv_p(mrb_value obj)
453{
454 switch (mrb_type(obj)) {
455 case MRB_TT_OBJECT:
456 case MRB_TT_CLASS:
457 case MRB_TT_MODULE:
458 case MRB_TT_SCLASS:
459 case MRB_TT_HASH:
460 case MRB_TT_DATA:
461 case MRB_TT_EXCEPTION:
462 return TRUE;
463 default:
464 return FALSE;
465 }
466}
467
468MRB_API mrb_value
469mrb_obj_iv_get(mrb_state *mrb, struct RObject *obj, mrb_sym sym)
470{
471 mrb_value v;
472
473 if (obj->iv && iv_get(mrb, obj->iv, sym, &v))
474 return v;
475 return mrb_nil_value();
476}
477
478MRB_API mrb_value
479mrb_iv_get(mrb_state *mrb, mrb_value obj, mrb_sym sym)
480{
481 if (obj_iv_p(obj)) {
482 return mrb_obj_iv_get(mrb, mrb_obj_ptr(obj), sym);
483 }
484 return mrb_nil_value();
485}
486
487MRB_API void
488mrb_obj_iv_set(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v)
489{
490 iv_tbl *t = obj->iv;
491
492 if (!t) {
493 t = obj->iv = iv_new(mrb);
494 }
495 mrb_write_barrier(mrb, (struct RBasic*)obj);
496 iv_put(mrb, t, sym, v);
497}
498
499MRB_API void
500mrb_obj_iv_ifnone(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v)
501{
502 iv_tbl *t = obj->iv;
503
504 if (!t) {
505 t = obj->iv = iv_new(mrb);
506 }
507 else if (iv_get(mrb, t, sym, &v)) {
508 return;
509 }
510 mrb_write_barrier(mrb, (struct RBasic*)obj);
511 iv_put(mrb, t, sym, v);
512}
513
514MRB_API void
515mrb_iv_set(mrb_state *mrb, mrb_value obj, mrb_sym sym, mrb_value v)
516{
517 if (obj_iv_p(obj)) {
518 mrb_obj_iv_set(mrb, mrb_obj_ptr(obj), sym, v);
519 }
520 else {
521 mrb_raise(mrb, E_ARGUMENT_ERROR, "cannot set instance variable");
522 }
523}
524
525MRB_API mrb_bool
526mrb_obj_iv_defined(mrb_state *mrb, struct RObject *obj, mrb_sym sym)
527{
528 iv_tbl *t;
529
530 t = obj->iv;
531 if (t) {
532 return iv_get(mrb, t, sym, NULL);
533 }
534 return FALSE;
535}
536
537MRB_API mrb_bool
538mrb_iv_defined(mrb_state *mrb, mrb_value obj, mrb_sym sym)
539{
540 if (!obj_iv_p(obj)) return FALSE;
541 return mrb_obj_iv_defined(mrb, mrb_obj_ptr(obj), sym);
542}
543
544#define identchar(c) (ISALNUM(c) || (c) == '_' || !ISASCII(c))
545
546MRB_API mrb_bool
547mrb_iv_p(mrb_state *mrb, mrb_sym iv_name)
548{
549 const char *s;
550 mrb_int i, len;
551
552 s = mrb_sym2name_len(mrb, iv_name, &len);
553 if (len < 2) return FALSE;
554 if (s[0] != '@') return FALSE;
555 if (s[1] == '@') return FALSE;
556 for (i=1; i<len; i++) {
557 if (!identchar(s[i])) return FALSE;
558 }
559 return TRUE;
560}
561
562MRB_API void
563mrb_iv_check(mrb_state *mrb, mrb_sym iv_name)
564{
565 if (!mrb_iv_p(mrb, iv_name)) {
566 mrb_name_error(mrb, iv_name, "'%S' is not allowed as an instance variable name", mrb_sym2str(mrb, iv_name));
567 }
568}
569
570MRB_API void
571mrb_iv_copy(mrb_state *mrb, mrb_value dest, mrb_value src)
572{
573 struct RObject *d = mrb_obj_ptr(dest);
574 struct RObject *s = mrb_obj_ptr(src);
575
576 if (d->iv) {
577 iv_free(mrb, d->iv);
578 d->iv = 0;
579 }
580 if (s->iv) {
581 mrb_write_barrier(mrb, (struct RBasic*)d);
582 d->iv = iv_copy(mrb, s->iv);
583 }
584}
585
586static int
587inspect_i(mrb_state *mrb, mrb_sym sym, mrb_value v, void *p)
588{
589 mrb_value str = *(mrb_value*)p;
590 const char *s;
591 mrb_int len;
592 mrb_value ins;
593 char *sp = RSTRING_PTR(str);
594
595 /* need not to show internal data */
596 if (sp[0] == '-') { /* first element */
597 sp[0] = '#';
598 mrb_str_cat_lit(mrb, str, " ");
599 }
600 else {
601 mrb_str_cat_lit(mrb, str, ", ");
602 }
603 s = mrb_sym2name_len(mrb, sym, &len);
604 mrb_str_cat(mrb, str, s, len);
605 mrb_str_cat_lit(mrb, str, "=");
606 if (mrb_type(v) == MRB_TT_OBJECT) {
607 ins = mrb_any_to_s(mrb, v);
608 }
609 else {
610 ins = mrb_inspect(mrb, v);
611 }
612 mrb_str_cat_str(mrb, str, ins);
613 return 0;
614}
615
616mrb_value
617mrb_obj_iv_inspect(mrb_state *mrb, struct RObject *obj)
618{
619 iv_tbl *t = obj->iv;
620 size_t len = iv_size(mrb, t);
621
622 if (len > 0) {
623 const char *cn = mrb_obj_classname(mrb, mrb_obj_value(obj));
624 mrb_value str = mrb_str_buf_new(mrb, 30);
625
626 mrb_str_cat_lit(mrb, str, "-<");
627 mrb_str_cat_cstr(mrb, str, cn);
628 mrb_str_cat_lit(mrb, str, ":");
629 mrb_str_concat(mrb, str, mrb_ptr_to_str(mrb, obj));
630
631 iv_foreach(mrb, t, inspect_i, &str);
632 mrb_str_cat_lit(mrb, str, ">");
633 return str;
634 }
635 return mrb_any_to_s(mrb, mrb_obj_value(obj));
636}
637
638MRB_API mrb_value
639mrb_iv_remove(mrb_state *mrb, mrb_value obj, mrb_sym sym)
640{
641 if (obj_iv_p(obj)) {
642 iv_tbl *t = mrb_obj_ptr(obj)->iv;
643 mrb_value val;
644
645 if (t && iv_del(mrb, t, sym, &val)) {
646 return val;
647 }
648 }
649 return mrb_undef_value();
650}
651
652mrb_value
653mrb_vm_iv_get(mrb_state *mrb, mrb_sym sym)
654{
655 /* get self */
656 return mrb_iv_get(mrb, mrb->c->stack[0], sym);
657}
658
659void
660mrb_vm_iv_set(mrb_state *mrb, mrb_sym sym, mrb_value v)
661{
662 /* get self */
663 mrb_iv_set(mrb, mrb->c->stack[0], sym, v);
664}
665
666static int
667iv_i(mrb_state *mrb, mrb_sym sym, mrb_value v, void *p)
668{
669 mrb_value ary;
670 const char* s;
671 mrb_int len;
672
673 ary = *(mrb_value*)p;
674 s = mrb_sym2name_len(mrb, sym, &len);
675 if (len > 1 && s[0] == '@' && s[1] != '@') {
676 mrb_ary_push(mrb, ary, mrb_symbol_value(sym));
677 }
678 return 0;
679}
680
681/* 15.3.1.3.23 */
682/*
683 * call-seq:
684 * obj.instance_variables -> array
685 *
686 * Returns an array of instance variable names for the receiver. Note
687 * that simply defining an accessor does not create the corresponding
688 * instance variable.
689 *
690 * class Fred
691 * attr_accessor :a1
692 * def initialize
693 * @iv = 3
694 * end
695 * end
696 * Fred.new.instance_variables #=> [:@iv]
697 */
698mrb_value
699mrb_obj_instance_variables(mrb_state *mrb, mrb_value self)
700{
701 mrb_value ary;
702
703 ary = mrb_ary_new(mrb);
704 if (obj_iv_p(self) && mrb_obj_ptr(self)->iv) {
705 iv_foreach(mrb, mrb_obj_ptr(self)->iv, iv_i, &ary);
706 }
707 return ary;
708}
709
710static int
711cv_i(mrb_state *mrb, mrb_sym sym, mrb_value v, void *p)
712{
713 mrb_value ary;
714 const char* s;
715 mrb_int len;
716
717 ary = *(mrb_value*)p;
718 s = mrb_sym2name_len(mrb, sym, &len);
719 if (len > 2 && s[0] == '@' && s[1] == '@') {
720 mrb_ary_push(mrb, ary, mrb_symbol_value(sym));
721 }
722 return 0;
723}
724
725/* 15.2.2.4.19 */
726/*
727 * call-seq:
728 * mod.class_variables -> array
729 *
730 * Returns an array of the names of class variables in <i>mod</i>.
731 *
732 * class One
733 * @@var1 = 1
734 * end
735 * class Two < One
736 * @@var2 = 2
737 * end
738 * One.class_variables #=> [:@@var1]
739 * Two.class_variables #=> [:@@var2]
740 */
741mrb_value
742mrb_mod_class_variables(mrb_state *mrb, mrb_value mod)
743{
744 mrb_value ary;
745 struct RClass *c;
746
747 ary = mrb_ary_new(mrb);
748 c = mrb_class_ptr(mod);
749 while (c) {
750 if (c->iv) {
751 iv_foreach(mrb, c->iv, cv_i, &ary);
752 }
753 c = c->super;
754 }
755 return ary;
756}
757
758MRB_API mrb_value
759mrb_mod_cv_get(mrb_state *mrb, struct RClass * c, mrb_sym sym)
760{
761 struct RClass * cls = c;
762 mrb_value v;
763
764 while (c) {
765 if (c->iv && iv_get(mrb, c->iv, sym, &v)) {
766 return v;
767 }
768 c = c->super;
769 }
770 if (cls && cls->tt == MRB_TT_SCLASS) {
771 mrb_value klass;
772
773 klass = mrb_obj_iv_get(mrb, (struct RObject *)cls,
774 mrb_intern_lit(mrb, "__attached__"));
775 c = mrb_class_ptr(klass);
776 if (c->tt == MRB_TT_CLASS) {
777 while (c) {
778 if (c->iv && iv_get(mrb, c->iv, sym, &v)) {
779 return v;
780 }
781 c = c->super;
782 }
783 }
784 }
785 mrb_name_error(mrb, sym, "uninitialized class variable %S in %S",
786 mrb_sym2str(mrb, sym), mrb_obj_value(cls));
787 /* not reached */
788 return mrb_nil_value();
789}
790
791MRB_API mrb_value
792mrb_cv_get(mrb_state *mrb, mrb_value mod, mrb_sym sym)
793{
794 return mrb_mod_cv_get(mrb, mrb_class_ptr(mod), sym);
795}
796
797MRB_API void
798mrb_mod_cv_set(mrb_state *mrb, struct RClass *c, mrb_sym sym, mrb_value v)
799{
800 struct RClass * cls = c;
801
802 while (c) {
803 if (c->iv) {
804 iv_tbl *t = c->iv;
805
806 if (iv_get(mrb, t, sym, NULL)) {
807 mrb_write_barrier(mrb, (struct RBasic*)c);
808 iv_put(mrb, t, sym, v);
809 return;
810 }
811 }
812 c = c->super;
813 }
814
815 if (!cls->iv) {
816 cls->iv = iv_new(mrb);
817 }
818
819 mrb_write_barrier(mrb, (struct RBasic*)cls);
820 iv_put(mrb, cls->iv, sym, v);
821}
822
823MRB_API void
824mrb_cv_set(mrb_state *mrb, mrb_value mod, mrb_sym sym, mrb_value v)
825{
826 mrb_mod_cv_set(mrb, mrb_class_ptr(mod), sym, v);
827}
828
829MRB_API mrb_bool
830mrb_mod_cv_defined(mrb_state *mrb, struct RClass * c, mrb_sym sym)
831{
832 while (c) {
833 if (c->iv) {
834 iv_tbl *t = c->iv;
835 if (iv_get(mrb, t, sym, NULL)) return TRUE;
836 }
837 c = c->super;
838 }
839
840 return FALSE;
841}
842
843MRB_API mrb_bool
844mrb_cv_defined(mrb_state *mrb, mrb_value mod, mrb_sym sym)
845{
846 return mrb_mod_cv_defined(mrb, mrb_class_ptr(mod), sym);
847}
848
849mrb_value
850mrb_vm_cv_get(mrb_state *mrb, mrb_sym sym)
851{
852 struct RClass *c = mrb->c->ci->proc->target_class;
853
854 if (!c) c = mrb->c->ci->target_class;
855
856 return mrb_mod_cv_get(mrb, c, sym);
857}
858
859void
860mrb_vm_cv_set(mrb_state *mrb, mrb_sym sym, mrb_value v)
861{
862 struct RClass *c = mrb->c->ci->proc->target_class;
863
864 if (!c) c = mrb->c->ci->target_class;
865 mrb_mod_cv_set(mrb, c, sym, v);
866}
867
868static void
869mod_const_check(mrb_state *mrb, mrb_value mod)
870{
871 switch (mrb_type(mod)) {
872 case MRB_TT_CLASS:
873 case MRB_TT_MODULE:
874 case MRB_TT_SCLASS:
875 break;
876 default:
877 mrb_raise(mrb, E_TYPE_ERROR, "constant look-up for non class/module");
878 break;
879 }
880}
881
882static mrb_value
883const_get(mrb_state *mrb, struct RClass *base, mrb_sym sym)
884{
885 struct RClass *c = base;
886 mrb_value v;
887 iv_tbl *t;
888 mrb_bool retry = FALSE;
889 mrb_value name;
890
891L_RETRY:
892 while (c) {
893 if (c->iv) {
894 t = c->iv;
895 if (iv_get(mrb, t, sym, &v))
896 return v;
897 }
898 c = c->super;
899 }
900 if (!retry && base && base->tt == MRB_TT_MODULE) {
901 c = mrb->object_class;
902 retry = TRUE;
903 goto L_RETRY;
904 }
905 name = mrb_symbol_value(sym);
906 return mrb_funcall_argv(mrb, mrb_obj_value(base), mrb_intern_lit(mrb, "const_missing"), 1, &name);
907}
908
909MRB_API mrb_value
910mrb_const_get(mrb_state *mrb, mrb_value mod, mrb_sym sym)
911{
912 mod_const_check(mrb, mod);
913 return const_get(mrb, mrb_class_ptr(mod), sym);
914}
915
916mrb_value
917mrb_vm_const_get(mrb_state *mrb, mrb_sym sym)
918{
919 struct RClass *c = mrb->c->ci->proc->target_class;
920
921 if (!c) c = mrb->c->ci->target_class;
922 if (c) {
923 struct RClass *c2;
924 mrb_value v;
925
926 if (c->iv && iv_get(mrb, c->iv, sym, &v)) {
927 return v;
928 }
929 if (c->tt == MRB_TT_SCLASS) {
930 mrb_value klass;
931 klass = mrb_obj_iv_get(mrb, (struct RObject *)c,
932 mrb_intern_lit(mrb, "__attached__"));
933 c2 = mrb_class_ptr(klass);
934 if (c2->tt == MRB_TT_CLASS)
935 c = c2;
936 }
937 c2 = c;
938 for (;;) {
939 c2 = mrb_class_outer_module(mrb, c2);
940 if (!c2) break;
941 if (c2->iv && iv_get(mrb, c2->iv, sym, &v)) {
942 return v;
943 }
944 }
945 }
946 return const_get(mrb, c, sym);
947}
948
949MRB_API void
950mrb_const_set(mrb_state *mrb, mrb_value mod, mrb_sym sym, mrb_value v)
951{
952 mod_const_check(mrb, mod);
953 mrb_iv_set(mrb, mod, sym, v);
954}
955
956void
957mrb_vm_const_set(mrb_state *mrb, mrb_sym sym, mrb_value v)
958{
959 struct RClass *c = mrb->c->ci->proc->target_class;
960
961 if (!c) c = mrb->c->ci->target_class;
962 mrb_obj_iv_set(mrb, (struct RObject*)c, sym, v);
963}
964
965MRB_API void
966mrb_const_remove(mrb_state *mrb, mrb_value mod, mrb_sym sym)
967{
968 mod_const_check(mrb, mod);
969 mrb_iv_remove(mrb, mod, sym);
970}
971
972MRB_API void
973mrb_define_const(mrb_state *mrb, struct RClass *mod, const char *name, mrb_value v)
974{
975 mrb_obj_iv_set(mrb, (struct RObject*)mod, mrb_intern_cstr(mrb, name), v);
976}
977
978MRB_API void
979mrb_define_global_const(mrb_state *mrb, const char *name, mrb_value val)
980{
981 mrb_define_const(mrb, mrb->object_class, name, val);
982}
983
984static int
985const_i(mrb_state *mrb, mrb_sym sym, mrb_value v, void *p)
986{
987 mrb_value ary;
988 const char* s;
989 mrb_int len;
990
991 ary = *(mrb_value*)p;
992 s = mrb_sym2name_len(mrb, sym, &len);
993 if (len >= 1 && ISUPPER(s[0])) {
994 mrb_ary_push(mrb, ary, mrb_symbol_value(sym));
995 }
996 return 0;
997}
998
999/* 15.2.2.4.24 */
1000/*
1001 * call-seq:
1002 * mod.constants -> array
1003 *
1004 * Returns an array of all names of contants defined in the receiver.
1005 */
1006mrb_value
1007mrb_mod_constants(mrb_state *mrb, mrb_value mod)
1008{
1009 mrb_value ary;
1010 mrb_bool inherit = TRUE;
1011 struct RClass *c = mrb_class_ptr(mod);
1012
1013 mrb_get_args(mrb, "|b", &inherit);
1014 ary = mrb_ary_new(mrb);
1015 while (c) {
1016 if (c->iv) {
1017 iv_foreach(mrb, c->iv, const_i, &ary);
1018 }
1019 if (!inherit) break;
1020 c = c->super;
1021 if (c == mrb->object_class) break;
1022 }
1023 return ary;
1024}
1025
1026MRB_API mrb_value
1027mrb_gv_get(mrb_state *mrb, mrb_sym sym)
1028{
1029 mrb_value v;
1030
1031 if (!mrb->globals) {
1032 return mrb_nil_value();
1033 }
1034 if (iv_get(mrb, mrb->globals, sym, &v))
1035 return v;
1036 return mrb_nil_value();
1037}
1038
1039MRB_API void
1040mrb_gv_set(mrb_state *mrb, mrb_sym sym, mrb_value v)
1041{
1042 iv_tbl *t;
1043
1044 if (!mrb->globals) {
1045 t = mrb->globals = iv_new(mrb);
1046 }
1047 else {
1048 t = mrb->globals;
1049 }
1050 iv_put(mrb, t, sym, v);
1051}
1052
1053MRB_API void
1054mrb_gv_remove(mrb_state *mrb, mrb_sym sym)
1055{
1056 if (!mrb->globals) {
1057 return;
1058 }
1059 iv_del(mrb, mrb->globals, sym, NULL);
1060}
1061
1062static int
1063gv_i(mrb_state *mrb, mrb_sym sym, mrb_value v, void *p)
1064{
1065 mrb_value ary;
1066
1067 ary = *(mrb_value*)p;
1068 mrb_ary_push(mrb, ary, mrb_symbol_value(sym));
1069 return 0;
1070}
1071
1072/* 15.3.1.2.4 */
1073/* 15.3.1.3.14 */
1074/*
1075 * call-seq:
1076 * global_variables -> array
1077 *
1078 * Returns an array of the names of global variables.
1079 *
1080 * global_variables.grep /std/ #=> [:$stdin, :$stdout, :$stderr]
1081 */
1082mrb_value
1083mrb_f_global_variables(mrb_state *mrb, mrb_value self)
1084{
1085 iv_tbl *t = mrb->globals;
1086 mrb_value ary = mrb_ary_new(mrb);
1087 size_t i;
1088 char buf[3];
1089
1090 if (t) {
1091 iv_foreach(mrb, t, gv_i, &ary);
1092 }
1093 buf[0] = '$';
1094 buf[2] = 0;
1095 for (i = 1; i <= 9; ++i) {
1096 buf[1] = (char)(i + '0');
1097 mrb_ary_push(mrb, ary, mrb_symbol_value(mrb_intern(mrb, buf, 2)));
1098 }
1099 return ary;
1100}
1101
1102static mrb_bool
1103mrb_const_defined_0(mrb_state *mrb, mrb_value mod, mrb_sym id, mrb_bool exclude, mrb_bool recurse)
1104{
1105 struct RClass *klass = mrb_class_ptr(mod);
1106 struct RClass *tmp;
1107 mrb_bool mod_retry = 0;
1108
1109 tmp = klass;
1110retry:
1111 while (tmp) {
1112 if (tmp->iv && iv_get(mrb, tmp->iv, id, NULL)) {
1113 return TRUE;
1114 }
1115 if (!recurse && (klass != mrb->object_class)) break;
1116 tmp = tmp->super;
1117 }
1118 if (!exclude && !mod_retry && (klass->tt == MRB_TT_MODULE)) {
1119 mod_retry = 1;
1120 tmp = mrb->object_class;
1121 goto retry;
1122 }
1123 return FALSE;
1124}
1125
1126MRB_API mrb_bool
1127mrb_const_defined(mrb_state *mrb, mrb_value mod, mrb_sym id)
1128{
1129 return mrb_const_defined_0(mrb, mod, id, TRUE, TRUE);
1130}
1131
1132MRB_API mrb_bool
1133mrb_const_defined_at(mrb_state *mrb, mrb_value mod, mrb_sym id)
1134{
1135 return mrb_const_defined_0(mrb, mod, id, TRUE, FALSE);
1136}
1137
1138MRB_API mrb_value
1139mrb_attr_get(mrb_state *mrb, mrb_value obj, mrb_sym id)
1140{
1141 return mrb_iv_get(mrb, obj, id);
1142}
1143
1144struct csym_arg {
1145 struct RClass *c;
1146 mrb_sym sym;
1147};
1148
1149static int
1150csym_i(mrb_state *mrb, mrb_sym sym, mrb_value v, void *p)
1151{
1152 struct csym_arg *a = (struct csym_arg*)p;
1153 struct RClass *c = a->c;
1154
1155 if (mrb_type(v) == c->tt && mrb_class_ptr(v) == c) {
1156 a->sym = sym;
1157 return 1; /* stop iteration */
1158 }
1159 return 0;
1160}
1161
1162mrb_sym
1163mrb_class_sym(mrb_state *mrb, struct RClass *c, struct RClass *outer)
1164{
1165 mrb_value name;
1166
1167 name = mrb_obj_iv_get(mrb, (struct RObject*)c, mrb_intern_lit(mrb, "__classid__"));
1168 if (mrb_nil_p(name)) {
1169
1170 if (!outer) return 0;
1171 else {
1172 struct csym_arg arg;
1173
1174 arg.c = c;
1175 arg.sym = 0;
1176 iv_foreach(mrb, outer->iv, csym_i, &arg);
1177 return arg.sym;
1178 }
1179 }
1180 return mrb_symbol(name);
1181}
Note: See TracBrowser for help on using the repository browser.