source: EcnlProtoTool/trunk/mruby-1.3.0/src/variable.c@ 331

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

prototoolに関連するプロジェクトをnewlibからmuslを使うよう変更・更新
ntshellをnewlibの下位の実装から、muslのsyscallの実装に変更・更新
以下のOSSをアップデート
・mruby-1.3.0
・musl-1.1.18
・onigmo-6.1.3
・tcc-0.9.27
以下のOSSを追加
・openssl-1.1.0e
・curl-7.57.0
・zlib-1.2.11
以下のmrbgemsを追加
・iij/mruby-digest
・iij/mruby-env
・iij/mruby-errno
・iij/mruby-iijson
・iij/mruby-ipaddr
・iij/mruby-mock
・iij/mruby-require
・iij/mruby-tls-openssl

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-csrc;charset=UTF-8
File size: 23.5 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 = (iv_tbl*)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 = (segment*)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 (MRB_FROZEN_P(obj)) {
493 mrb_raisef(mrb, E_RUNTIME_ERROR, "can't modify frozen %S", mrb_obj_value(obj));
494 }
495 if (!t) {
496 t = obj->iv = iv_new(mrb);
497 }
498 mrb_write_barrier(mrb, (struct RBasic*)obj);
499 iv_put(mrb, t, sym, v);
500}
501
502MRB_API void
503mrb_obj_iv_ifnone(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v)
504{
505 iv_tbl *t = obj->iv;
506
507 if (!t) {
508 t = obj->iv = iv_new(mrb);
509 }
510 else if (iv_get(mrb, t, sym, &v)) {
511 return;
512 }
513 mrb_write_barrier(mrb, (struct RBasic*)obj);
514 iv_put(mrb, t, sym, v);
515}
516
517MRB_API void
518mrb_iv_set(mrb_state *mrb, mrb_value obj, mrb_sym sym, mrb_value v)
519{
520 if (obj_iv_p(obj)) {
521 mrb_obj_iv_set(mrb, mrb_obj_ptr(obj), sym, v);
522 }
523 else {
524 mrb_raise(mrb, E_ARGUMENT_ERROR, "cannot set instance variable");
525 }
526}
527
528MRB_API mrb_bool
529mrb_obj_iv_defined(mrb_state *mrb, struct RObject *obj, mrb_sym sym)
530{
531 iv_tbl *t;
532
533 t = obj->iv;
534 if (t) {
535 return iv_get(mrb, t, sym, NULL);
536 }
537 return FALSE;
538}
539
540MRB_API mrb_bool
541mrb_iv_defined(mrb_state *mrb, mrb_value obj, mrb_sym sym)
542{
543 if (!obj_iv_p(obj)) return FALSE;
544 return mrb_obj_iv_defined(mrb, mrb_obj_ptr(obj), sym);
545}
546
547#define identchar(c) (ISALNUM(c) || (c) == '_' || !ISASCII(c))
548
549MRB_API mrb_bool
550mrb_iv_p(mrb_state *mrb, mrb_sym iv_name)
551{
552 const char *s;
553 mrb_int i, len;
554
555 s = mrb_sym2name_len(mrb, iv_name, &len);
556 if (len < 2) return FALSE;
557 if (s[0] != '@') return FALSE;
558 if (s[1] == '@') return FALSE;
559 for (i=1; i<len; i++) {
560 if (!identchar(s[i])) return FALSE;
561 }
562 return TRUE;
563}
564
565MRB_API void
566mrb_iv_check(mrb_state *mrb, mrb_sym iv_name)
567{
568 if (!mrb_iv_p(mrb, iv_name)) {
569 mrb_name_error(mrb, iv_name, "'%S' is not allowed as an instance variable name", mrb_sym2str(mrb, iv_name));
570 }
571}
572
573MRB_API void
574mrb_iv_copy(mrb_state *mrb, mrb_value dest, mrb_value src)
575{
576 struct RObject *d = mrb_obj_ptr(dest);
577 struct RObject *s = mrb_obj_ptr(src);
578
579 if (d->iv) {
580 iv_free(mrb, d->iv);
581 d->iv = 0;
582 }
583 if (s->iv) {
584 mrb_write_barrier(mrb, (struct RBasic*)d);
585 d->iv = iv_copy(mrb, s->iv);
586 }
587}
588
589static int
590inspect_i(mrb_state *mrb, mrb_sym sym, mrb_value v, void *p)
591{
592 mrb_value str = *(mrb_value*)p;
593 const char *s;
594 mrb_int len;
595 mrb_value ins;
596 char *sp = RSTRING_PTR(str);
597
598 /* need not to show internal data */
599 if (sp[0] == '-') { /* first element */
600 sp[0] = '#';
601 mrb_str_cat_lit(mrb, str, " ");
602 }
603 else {
604 mrb_str_cat_lit(mrb, str, ", ");
605 }
606 s = mrb_sym2name_len(mrb, sym, &len);
607 mrb_str_cat(mrb, str, s, len);
608 mrb_str_cat_lit(mrb, str, "=");
609 if (mrb_type(v) == MRB_TT_OBJECT) {
610 ins = mrb_any_to_s(mrb, v);
611 }
612 else {
613 ins = mrb_inspect(mrb, v);
614 }
615 mrb_str_cat_str(mrb, str, ins);
616 return 0;
617}
618
619mrb_value
620mrb_obj_iv_inspect(mrb_state *mrb, struct RObject *obj)
621{
622 iv_tbl *t = obj->iv;
623 size_t len = iv_size(mrb, t);
624
625 if (len > 0) {
626 const char *cn = mrb_obj_classname(mrb, mrb_obj_value(obj));
627 mrb_value str = mrb_str_buf_new(mrb, 30);
628
629 mrb_str_cat_lit(mrb, str, "-<");
630 mrb_str_cat_cstr(mrb, str, cn);
631 mrb_str_cat_lit(mrb, str, ":");
632 mrb_str_concat(mrb, str, mrb_ptr_to_str(mrb, obj));
633
634 iv_foreach(mrb, t, inspect_i, &str);
635 mrb_str_cat_lit(mrb, str, ">");
636 return str;
637 }
638 return mrb_any_to_s(mrb, mrb_obj_value(obj));
639}
640
641MRB_API mrb_value
642mrb_iv_remove(mrb_state *mrb, mrb_value obj, mrb_sym sym)
643{
644 if (obj_iv_p(obj)) {
645 iv_tbl *t = mrb_obj_ptr(obj)->iv;
646 mrb_value val;
647
648 if (t && iv_del(mrb, t, sym, &val)) {
649 return val;
650 }
651 }
652 return mrb_undef_value();
653}
654
655mrb_value
656mrb_vm_iv_get(mrb_state *mrb, mrb_sym sym)
657{
658 /* get self */
659 return mrb_iv_get(mrb, mrb->c->stack[0], sym);
660}
661
662void
663mrb_vm_iv_set(mrb_state *mrb, mrb_sym sym, mrb_value v)
664{
665 /* get self */
666 mrb_iv_set(mrb, mrb->c->stack[0], sym, v);
667}
668
669static int
670iv_i(mrb_state *mrb, mrb_sym sym, mrb_value v, void *p)
671{
672 mrb_value ary;
673 const char* s;
674 mrb_int len;
675
676 ary = *(mrb_value*)p;
677 s = mrb_sym2name_len(mrb, sym, &len);
678 if (len > 1 && s[0] == '@' && s[1] != '@') {
679 mrb_ary_push(mrb, ary, mrb_symbol_value(sym));
680 }
681 return 0;
682}
683
684/* 15.3.1.3.23 */
685/*
686 * call-seq:
687 * obj.instance_variables -> array
688 *
689 * Returns an array of instance variable names for the receiver. Note
690 * that simply defining an accessor does not create the corresponding
691 * instance variable.
692 *
693 * class Fred
694 * attr_accessor :a1
695 * def initialize
696 * @iv = 3
697 * end
698 * end
699 * Fred.new.instance_variables #=> [:@iv]
700 */
701mrb_value
702mrb_obj_instance_variables(mrb_state *mrb, mrb_value self)
703{
704 mrb_value ary;
705
706 ary = mrb_ary_new(mrb);
707 if (obj_iv_p(self) && mrb_obj_ptr(self)->iv) {
708 iv_foreach(mrb, mrb_obj_ptr(self)->iv, iv_i, &ary);
709 }
710 return ary;
711}
712
713static int
714cv_i(mrb_state *mrb, mrb_sym sym, mrb_value v, void *p)
715{
716 mrb_value ary;
717 const char* s;
718 mrb_int len;
719
720 ary = *(mrb_value*)p;
721 s = mrb_sym2name_len(mrb, sym, &len);
722 if (len > 2 && s[0] == '@' && s[1] == '@') {
723 mrb_ary_push(mrb, ary, mrb_symbol_value(sym));
724 }
725 return 0;
726}
727
728/* 15.2.2.4.19 */
729/*
730 * call-seq:
731 * mod.class_variables -> array
732 *
733 * Returns an array of the names of class variables in <i>mod</i>.
734 *
735 * class One
736 * @@var1 = 1
737 * end
738 * class Two < One
739 * @@var2 = 2
740 * end
741 * One.class_variables #=> [:@@var1]
742 * Two.class_variables #=> [:@@var2]
743 */
744mrb_value
745mrb_mod_class_variables(mrb_state *mrb, mrb_value mod)
746{
747 mrb_value ary;
748 struct RClass *c;
749
750 ary = mrb_ary_new(mrb);
751 c = mrb_class_ptr(mod);
752 while (c) {
753 if (c->iv) {
754 iv_foreach(mrb, c->iv, cv_i, &ary);
755 }
756 c = c->super;
757 }
758 return ary;
759}
760
761MRB_API mrb_value
762mrb_mod_cv_get(mrb_state *mrb, struct RClass *c, mrb_sym sym)
763{
764 struct RClass * cls = c;
765 mrb_value v;
766 int given = FALSE;
767
768 while (c) {
769 if (c->iv && iv_get(mrb, c->iv, sym, &v)) {
770 given = TRUE;
771 }
772 c = c->super;
773 }
774 if (given) return v;
775 if (cls && cls->tt == MRB_TT_SCLASS) {
776 mrb_value klass;
777
778 klass = mrb_obj_iv_get(mrb, (struct RObject *)cls,
779 mrb_intern_lit(mrb, "__attached__"));
780 c = mrb_class_ptr(klass);
781 if (c->tt == MRB_TT_CLASS || c->tt == MRB_TT_MODULE) {
782 given = FALSE;
783 while (c) {
784 if (c->iv && iv_get(mrb, c->iv, sym, &v)) {
785 given = TRUE;
786 }
787 c = c->super;
788 }
789 if (given) return v;
790 }
791 }
792 mrb_name_error(mrb, sym, "uninitialized class variable %S in %S",
793 mrb_sym2str(mrb, sym), mrb_obj_value(cls));
794 /* not reached */
795 return mrb_nil_value();
796}
797
798MRB_API mrb_value
799mrb_cv_get(mrb_state *mrb, mrb_value mod, mrb_sym sym)
800{
801 return mrb_mod_cv_get(mrb, mrb_class_ptr(mod), sym);
802}
803
804MRB_API void
805mrb_mod_cv_set(mrb_state *mrb, struct RClass *c, mrb_sym sym, mrb_value v)
806{
807 struct RClass * cls = c;
808
809 while (c) {
810 if (c->iv) {
811 iv_tbl *t = c->iv;
812
813 if (iv_get(mrb, t, sym, NULL)) {
814 mrb_write_barrier(mrb, (struct RBasic*)c);
815 iv_put(mrb, t, sym, v);
816 return;
817 }
818 }
819 c = c->super;
820 }
821
822 if (cls && cls->tt == MRB_TT_SCLASS) {
823 mrb_value klass;
824
825 klass = mrb_obj_iv_get(mrb, (struct RObject*)cls,
826 mrb_intern_lit(mrb, "__attached__"));
827 switch (mrb_type(klass)) {
828 case MRB_TT_CLASS:
829 case MRB_TT_MODULE:
830 case MRB_TT_SCLASS:
831 c = mrb_class_ptr(klass);
832 break;
833 default:
834 c = cls;
835 break;
836 }
837 }
838 else{
839 c = cls;
840 }
841
842 if (!c->iv) {
843 c->iv = iv_new(mrb);
844 }
845
846 mrb_write_barrier(mrb, (struct RBasic*)c);
847 iv_put(mrb, c->iv, sym, v);
848}
849
850MRB_API void
851mrb_cv_set(mrb_state *mrb, mrb_value mod, mrb_sym sym, mrb_value v)
852{
853 mrb_mod_cv_set(mrb, mrb_class_ptr(mod), sym, v);
854}
855
856MRB_API mrb_bool
857mrb_mod_cv_defined(mrb_state *mrb, struct RClass * c, mrb_sym sym)
858{
859 while (c) {
860 if (c->iv) {
861 iv_tbl *t = c->iv;
862 if (iv_get(mrb, t, sym, NULL)) return TRUE;
863 }
864 c = c->super;
865 }
866
867 return FALSE;
868}
869
870MRB_API mrb_bool
871mrb_cv_defined(mrb_state *mrb, mrb_value mod, mrb_sym sym)
872{
873 return mrb_mod_cv_defined(mrb, mrb_class_ptr(mod), sym);
874}
875
876mrb_value
877mrb_vm_cv_get(mrb_state *mrb, mrb_sym sym)
878{
879 struct RClass *c = mrb->c->ci->proc->target_class;
880
881 if (!c) c = mrb->c->ci->target_class;
882
883 return mrb_mod_cv_get(mrb, c, sym);
884}
885
886void
887mrb_vm_cv_set(mrb_state *mrb, mrb_sym sym, mrb_value v)
888{
889 struct RClass *c = mrb->c->ci->proc->target_class;
890
891 if (!c) c = mrb->c->ci->target_class;
892 mrb_mod_cv_set(mrb, c, sym, v);
893}
894
895static void
896mod_const_check(mrb_state *mrb, mrb_value mod)
897{
898 switch (mrb_type(mod)) {
899 case MRB_TT_CLASS:
900 case MRB_TT_MODULE:
901 case MRB_TT_SCLASS:
902 break;
903 default:
904 mrb_raise(mrb, E_TYPE_ERROR, "constant look-up for non class/module");
905 break;
906 }
907}
908
909static mrb_value
910const_get(mrb_state *mrb, struct RClass *base, mrb_sym sym)
911{
912 struct RClass *c = base;
913 mrb_value v;
914 iv_tbl *t;
915 mrb_bool retry = FALSE;
916 mrb_value name;
917
918L_RETRY:
919 while (c) {
920 if (c->iv) {
921 t = c->iv;
922 if (iv_get(mrb, t, sym, &v))
923 return v;
924 }
925 c = c->super;
926 }
927 if (!retry && base && base->tt == MRB_TT_MODULE) {
928 c = mrb->object_class;
929 retry = TRUE;
930 goto L_RETRY;
931 }
932 name = mrb_symbol_value(sym);
933 return mrb_funcall_argv(mrb, mrb_obj_value(base), mrb_intern_lit(mrb, "const_missing"), 1, &name);
934}
935
936MRB_API mrb_value
937mrb_const_get(mrb_state *mrb, mrb_value mod, mrb_sym sym)
938{
939 mod_const_check(mrb, mod);
940 return const_get(mrb, mrb_class_ptr(mod), sym);
941}
942
943mrb_value
944mrb_vm_const_get(mrb_state *mrb, mrb_sym sym)
945{
946 struct RClass *c = mrb->c->ci->proc->target_class;
947
948 if (!c) c = mrb->c->ci->target_class;
949 if (c) {
950 struct RClass *c2;
951 mrb_value v;
952
953 if (c->iv && iv_get(mrb, c->iv, sym, &v)) {
954 return v;
955 }
956 c2 = c;
957 while (c2 && c2->tt == MRB_TT_SCLASS) {
958 mrb_value klass;
959 klass = mrb_obj_iv_get(mrb, (struct RObject *)c2,
960 mrb_intern_lit(mrb, "__attached__"));
961 c2 = mrb_class_ptr(klass);
962 }
963 if (c2->tt == MRB_TT_CLASS || c2->tt == MRB_TT_MODULE) c = c2;
964 c2 = c;
965 for (;;) {
966 c2 = mrb_class_outer_module(mrb, c2);
967 if (!c2) break;
968 if (c2->iv && iv_get(mrb, c2->iv, sym, &v)) {
969 return v;
970 }
971 }
972 }
973 return const_get(mrb, c, sym);
974}
975
976MRB_API void
977mrb_const_set(mrb_state *mrb, mrb_value mod, mrb_sym sym, mrb_value v)
978{
979 mod_const_check(mrb, mod);
980 mrb_iv_set(mrb, mod, sym, v);
981}
982
983void
984mrb_vm_const_set(mrb_state *mrb, mrb_sym sym, mrb_value v)
985{
986 struct RClass *c = mrb->c->ci->proc->target_class;
987
988 if (!c) c = mrb->c->ci->target_class;
989 mrb_obj_iv_set(mrb, (struct RObject*)c, sym, v);
990}
991
992MRB_API void
993mrb_const_remove(mrb_state *mrb, mrb_value mod, mrb_sym sym)
994{
995 mod_const_check(mrb, mod);
996 mrb_iv_remove(mrb, mod, sym);
997}
998
999MRB_API void
1000mrb_define_const(mrb_state *mrb, struct RClass *mod, const char *name, mrb_value v)
1001{
1002 mrb_obj_iv_set(mrb, (struct RObject*)mod, mrb_intern_cstr(mrb, name), v);
1003}
1004
1005MRB_API void
1006mrb_define_global_const(mrb_state *mrb, const char *name, mrb_value val)
1007{
1008 mrb_define_const(mrb, mrb->object_class, name, val);
1009}
1010
1011static int
1012const_i(mrb_state *mrb, mrb_sym sym, mrb_value v, void *p)
1013{
1014 mrb_value ary;
1015 const char* s;
1016 mrb_int len;
1017
1018 ary = *(mrb_value*)p;
1019 s = mrb_sym2name_len(mrb, sym, &len);
1020 if (len >= 1 && ISUPPER(s[0])) {
1021 mrb_ary_push(mrb, ary, mrb_symbol_value(sym));
1022 }
1023 return 0;
1024}
1025
1026/* 15.2.2.4.24 */
1027/*
1028 * call-seq:
1029 * mod.constants -> array
1030 *
1031 * Returns an array of all names of contants defined in the receiver.
1032 */
1033mrb_value
1034mrb_mod_constants(mrb_state *mrb, mrb_value mod)
1035{
1036 mrb_value ary;
1037 mrb_bool inherit = TRUE;
1038 struct RClass *c = mrb_class_ptr(mod);
1039
1040 mrb_get_args(mrb, "|b", &inherit);
1041 ary = mrb_ary_new(mrb);
1042 while (c) {
1043 if (c->iv) {
1044 iv_foreach(mrb, c->iv, const_i, &ary);
1045 }
1046 if (!inherit) break;
1047 c = c->super;
1048 if (c == mrb->object_class) break;
1049 }
1050 return ary;
1051}
1052
1053MRB_API mrb_value
1054mrb_gv_get(mrb_state *mrb, mrb_sym sym)
1055{
1056 mrb_value v;
1057
1058 if (!mrb->globals) {
1059 return mrb_nil_value();
1060 }
1061 if (iv_get(mrb, mrb->globals, sym, &v))
1062 return v;
1063 return mrb_nil_value();
1064}
1065
1066MRB_API void
1067mrb_gv_set(mrb_state *mrb, mrb_sym sym, mrb_value v)
1068{
1069 iv_tbl *t;
1070
1071 if (!mrb->globals) {
1072 t = mrb->globals = iv_new(mrb);
1073 }
1074 else {
1075 t = mrb->globals;
1076 }
1077 iv_put(mrb, t, sym, v);
1078}
1079
1080MRB_API void
1081mrb_gv_remove(mrb_state *mrb, mrb_sym sym)
1082{
1083 if (!mrb->globals) {
1084 return;
1085 }
1086 iv_del(mrb, mrb->globals, sym, NULL);
1087}
1088
1089static int
1090gv_i(mrb_state *mrb, mrb_sym sym, mrb_value v, void *p)
1091{
1092 mrb_value ary;
1093
1094 ary = *(mrb_value*)p;
1095 mrb_ary_push(mrb, ary, mrb_symbol_value(sym));
1096 return 0;
1097}
1098
1099/* 15.3.1.2.4 */
1100/* 15.3.1.3.14 */
1101/*
1102 * call-seq:
1103 * global_variables -> array
1104 *
1105 * Returns an array of the names of global variables.
1106 *
1107 * global_variables.grep /std/ #=> [:$stdin, :$stdout, :$stderr]
1108 */
1109mrb_value
1110mrb_f_global_variables(mrb_state *mrb, mrb_value self)
1111{
1112 iv_tbl *t = mrb->globals;
1113 mrb_value ary = mrb_ary_new(mrb);
1114 size_t i;
1115 char buf[3];
1116
1117 if (t) {
1118 iv_foreach(mrb, t, gv_i, &ary);
1119 }
1120 buf[0] = '$';
1121 buf[2] = 0;
1122 for (i = 1; i <= 9; ++i) {
1123 buf[1] = (char)(i + '0');
1124 mrb_ary_push(mrb, ary, mrb_symbol_value(mrb_intern(mrb, buf, 2)));
1125 }
1126 return ary;
1127}
1128
1129static mrb_bool
1130mrb_const_defined_0(mrb_state *mrb, mrb_value mod, mrb_sym id, mrb_bool exclude, mrb_bool recurse)
1131{
1132 struct RClass *klass = mrb_class_ptr(mod);
1133 struct RClass *tmp;
1134 mrb_bool mod_retry = 0;
1135
1136 tmp = klass;
1137retry:
1138 while (tmp) {
1139 if (tmp->iv && iv_get(mrb, tmp->iv, id, NULL)) {
1140 return TRUE;
1141 }
1142 if (!recurse && (klass != mrb->object_class)) break;
1143 tmp = tmp->super;
1144 }
1145 if (!exclude && !mod_retry && (klass->tt == MRB_TT_MODULE)) {
1146 mod_retry = 1;
1147 tmp = mrb->object_class;
1148 goto retry;
1149 }
1150 return FALSE;
1151}
1152
1153MRB_API mrb_bool
1154mrb_const_defined(mrb_state *mrb, mrb_value mod, mrb_sym id)
1155{
1156 return mrb_const_defined_0(mrb, mod, id, TRUE, TRUE);
1157}
1158
1159MRB_API mrb_bool
1160mrb_const_defined_at(mrb_state *mrb, mrb_value mod, mrb_sym id)
1161{
1162 return mrb_const_defined_0(mrb, mod, id, TRUE, FALSE);
1163}
1164
1165MRB_API mrb_value
1166mrb_attr_get(mrb_state *mrb, mrb_value obj, mrb_sym id)
1167{
1168 return mrb_iv_get(mrb, obj, id);
1169}
1170
1171struct csym_arg {
1172 struct RClass *c;
1173 mrb_sym sym;
1174};
1175
1176static int
1177csym_i(mrb_state *mrb, mrb_sym sym, mrb_value v, void *p)
1178{
1179 struct csym_arg *a = (struct csym_arg*)p;
1180 struct RClass *c = a->c;
1181
1182 if (mrb_type(v) == c->tt && mrb_class_ptr(v) == c) {
1183 a->sym = sym;
1184 return 1; /* stop iteration */
1185 }
1186 return 0;
1187}
1188
1189mrb_sym
1190mrb_class_sym(mrb_state *mrb, struct RClass *c, struct RClass *outer)
1191{
1192 mrb_value name;
1193
1194 name = mrb_obj_iv_get(mrb, (struct RObject*)c, mrb_intern_lit(mrb, "__classid__"));
1195 if (mrb_nil_p(name)) {
1196
1197 if (!outer) return 0;
1198 else {
1199 struct csym_arg arg;
1200
1201 arg.c = c;
1202 arg.sym = 0;
1203 iv_foreach(mrb, outer->iv, csym_i, &arg);
1204 return arg.sym;
1205 }
1206 }
1207 return mrb_symbol(name);
1208}
Note: See TracBrowser for help on using the repository browser.