2 ** struct.c - Struct class
4 ** See Copyright Notice in mruby.h
10 #include "mruby/array.h"
11 #include "mruby/string.h"
12 #include "mruby/class.h"
13 #include "mruby/variable.h"
14 #include "mruby/hash.h"
15 #include "mruby/range.h"
17 #define RSTRUCT_LEN(st) RARRAY_LEN(st)
18 #define RSTRUCT_PTR(st) RARRAY_PTR(st)
20 static struct RClass
*
21 struct_class(mrb_state
*mrb
)
23 return mrb_class_get(mrb
, "Struct");
26 static inline mrb_value
27 struct_ivar_get(mrb_state
*mrb
, mrb_value c
, mrb_sym id
)
29 struct RClass
* kclass
;
30 struct RClass
* sclass
= struct_class(mrb
);
34 ans
= mrb_iv_get(mrb
, c
, id
);
35 if (!mrb_nil_p(ans
)) return ans
;
36 kclass
= RCLASS_SUPER(c
);
37 if (kclass
== 0 || kclass
== sclass
)
38 return mrb_nil_value();
39 c
= mrb_obj_value(kclass
);
44 mrb_struct_s_members(mrb_state
*mrb
, mrb_value klass
)
46 mrb_value members
= struct_ivar_get(mrb
, klass
, mrb_intern_lit(mrb
, "__members__"));
48 if (mrb_nil_p(members
)) {
49 mrb_raise(mrb
, E_TYPE_ERROR
, "uninitialized struct");
51 if (!mrb_array_p(members
)) {
52 mrb_raise(mrb
, E_TYPE_ERROR
, "corrupted struct");
58 mrb_struct_members(mrb_state
*mrb
, mrb_value s
)
60 mrb_value members
= mrb_struct_s_members(mrb
, mrb_obj_value(mrb_obj_class(mrb
, s
)));
61 if (!strcmp(mrb_class_name(mrb
, mrb_obj_class(mrb
, s
)), "Struct")) {
62 if (RSTRUCT_LEN(s
) != RARRAY_LEN(members
)) {
63 mrb_raisef(mrb
, E_TYPE_ERROR
,
64 "struct size differs (%S required %S given)",
65 mrb_fixnum_value(RARRAY_LEN(members
)), mrb_fixnum_value(RSTRUCT_LEN(s
)));
72 mrb_struct_s_members_m(mrb_state
*mrb
, mrb_value klass
)
74 mrb_value members
, ary
;
77 members
= mrb_struct_s_members(mrb
, klass
);
78 ary
= mrb_ary_new_capa(mrb
, RARRAY_LEN(members
));
79 p
= RARRAY_PTR(members
); pend
= p
+ RARRAY_LEN(members
);
81 mrb_ary_push(mrb
, ary
, *p
);
90 * struct.members -> array
92 * Returns an array of strings representing the names of the instance
95 * Customer = Struct.new(:name, :address, :zip)
96 * joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
97 * joe.members #=> [:name, :address, :zip]
101 mrb_struct_members_m(mrb_state
*mrb
, mrb_value obj
)
103 return mrb_struct_s_members_m(mrb
, mrb_obj_value(mrb_obj_class(mrb
, obj
)));
107 mrb_struct_getmember(mrb_state
*mrb
, mrb_value obj
, mrb_sym id
)
109 mrb_value members
, slot
, *ptr
, *ptr_members
;
112 ptr
= RSTRUCT_PTR(obj
);
113 members
= mrb_struct_members(mrb
, obj
);
114 ptr_members
= RARRAY_PTR(members
);
115 slot
= mrb_symbol_value(id
);
116 len
= RARRAY_LEN(members
);
117 for (i
=0; i
<len
; i
++) {
118 if (mrb_obj_equal(mrb
, ptr_members
[i
], slot
)) {
122 mrb_raisef(mrb
, E_INDEX_ERROR
, "`%S' is not a struct member", mrb_sym2str(mrb
, id
));
123 return mrb_nil_value(); /* not reached */
127 mrb_struct_ref(mrb_state
*mrb
, mrb_value obj
)
129 return mrb_struct_getmember(mrb
, obj
, mrb
->c
->ci
->mid
);
132 static mrb_value
mrb_struct_ref0(mrb_state
* mrb
, mrb_value obj
) {return RSTRUCT_PTR(obj
)[0];}
133 static mrb_value
mrb_struct_ref1(mrb_state
* mrb
, mrb_value obj
) {return RSTRUCT_PTR(obj
)[1];}
134 static mrb_value
mrb_struct_ref2(mrb_state
* mrb
, mrb_value obj
) {return RSTRUCT_PTR(obj
)[2];}
135 static mrb_value
mrb_struct_ref3(mrb_state
* mrb
, mrb_value obj
) {return RSTRUCT_PTR(obj
)[3];}
136 static mrb_value
mrb_struct_ref4(mrb_state
* mrb
, mrb_value obj
) {return RSTRUCT_PTR(obj
)[4];}
137 static mrb_value
mrb_struct_ref5(mrb_state
* mrb
, mrb_value obj
) {return RSTRUCT_PTR(obj
)[5];}
138 static mrb_value
mrb_struct_ref6(mrb_state
* mrb
, mrb_value obj
) {return RSTRUCT_PTR(obj
)[6];}
139 static mrb_value
mrb_struct_ref7(mrb_state
* mrb
, mrb_value obj
) {return RSTRUCT_PTR(obj
)[7];}
140 static mrb_value
mrb_struct_ref8(mrb_state
* mrb
, mrb_value obj
) {return RSTRUCT_PTR(obj
)[8];}
141 static mrb_value
mrb_struct_ref9(mrb_state
* mrb
, mrb_value obj
) {return RSTRUCT_PTR(obj
)[9];}
143 #define numberof(array) (int)(sizeof(array) / sizeof((array)[0]))
144 #define N_REF_FUNC numberof(ref_func)
146 static const mrb_func_t ref_func
[] = {
160 mrb_id_attrset(mrb_state
*mrb
, mrb_sym id
)
167 name
= mrb_sym2name_len(mrb
, id
, &len
);
168 buf
= (char *)mrb_malloc(mrb
, (size_t)len
+2);
169 memcpy(buf
, name
, (size_t)len
);
173 mid
= mrb_intern(mrb
, buf
, len
+1);
179 mrb_struct_set(mrb_state
*mrb
, mrb_value obj
, mrb_value val
)
182 mrb_int i
, len
, slen
;
184 mrb_value members
, slot
, *ptr
, *ptr_members
;
187 name
= mrb_sym2name_len(mrb
, mrb
->c
->ci
->mid
, &slen
);
188 mid
= mrb_intern(mrb
, name
, slen
-1); /* omit last "=" */
190 members
= mrb_struct_members(mrb
, obj
);
191 ptr_members
= RARRAY_PTR(members
);
192 len
= RARRAY_LEN(members
);
193 ptr
= RSTRUCT_PTR(obj
);
194 for (i
=0; i
<len
; i
++) {
195 slot
= ptr_members
[i
];
196 if (mrb_symbol(slot
) == mid
) {
200 mrb_raisef(mrb
, E_INDEX_ERROR
, "`%S' is not a struct member", mrb_sym2str(mrb
, mid
));
201 return mrb_nil_value(); /* not reached */
205 mrb_struct_set_m(mrb_state
*mrb
, mrb_value obj
)
209 mrb_get_args(mrb
, "o", &val
);
210 return mrb_struct_set(mrb
, obj
, val
);
214 is_local_id(mrb_state
*mrb
, const char *name
)
216 if (!name
) return FALSE
;
217 return !ISUPPER(name
[0]);
221 is_const_id(mrb_state
*mrb
, const char *name
)
223 if (!name
) return FALSE
;
224 return ISUPPER(name
[0]);
228 make_struct_define_accessors(mrb_state
*mrb
, mrb_value members
, struct RClass
*c
)
230 mrb_value
*ptr_members
= RARRAY_PTR(members
);
232 mrb_int len
= RARRAY_LEN(members
);
233 int ai
= mrb_gc_arena_save(mrb
);
235 for (i
=0; i
<len
; i
++) {
236 mrb_sym id
= mrb_symbol(ptr_members
[i
]);
237 const char *name
= mrb_sym2name_len(mrb
, id
, NULL
);
239 if (is_local_id(mrb
, name
) || is_const_id(mrb
, name
)) {
240 if (i
< N_REF_FUNC
) {
241 mrb_define_method_id(mrb
, c
, id
, ref_func
[i
], MRB_ARGS_NONE());
244 mrb_define_method_id(mrb
, c
, id
, mrb_struct_ref
, MRB_ARGS_NONE());
246 mrb_define_method_id(mrb
, c
, mrb_id_attrset(mrb
, id
), mrb_struct_set_m
, MRB_ARGS_REQ(1));
247 mrb_gc_arena_restore(mrb
, ai
);
253 make_struct(mrb_state
*mrb
, mrb_value name
, mrb_value members
, struct RClass
* klass
)
259 if (mrb_nil_p(name
)) {
260 c
= mrb_class_new(mrb
, klass
);
263 /* old style: should we warn? */
264 name
= mrb_str_to_str(mrb
, name
);
265 id
= mrb_obj_to_sym(mrb
, name
);
266 if (!is_const_id(mrb
, mrb_sym2name_len(mrb
, id
, NULL
))) {
267 mrb_name_error(mrb
, id
, "identifier %S needs to be constant", name
);
269 if (mrb_const_defined_at(mrb
, klass
, id
)) {
270 mrb_warn(mrb
, "redefining constant Struct::%S", name
);
271 /* ?rb_mod_remove_const(klass, mrb_sym2name(mrb, id)); */
273 c
= mrb_define_class_under(mrb
, klass
, RSTRING_PTR(name
), klass
);
275 MRB_SET_INSTANCE_TT(c
, MRB_TT_ARRAY
);
276 nstr
= mrb_obj_value(c
);
277 mrb_iv_set(mrb
, nstr
, mrb_intern_lit(mrb
, "__members__"), members
);
279 mrb_define_class_method(mrb
, c
, "new", mrb_instance_new
, MRB_ARGS_ANY());
280 mrb_define_class_method(mrb
, c
, "[]", mrb_instance_new
, MRB_ARGS_ANY());
281 mrb_define_class_method(mrb
, c
, "members", mrb_struct_s_members_m
, MRB_ARGS_NONE());
282 /* RSTRUCT(nstr)->basic.c->super = c->c; */
283 make_struct_define_accessors(mrb
, members
, c
);
290 * Struct.new( [aString] [, aSym]+> ) -> StructClass
291 * StructClass.new(arg, ...) -> obj
292 * StructClass[arg, ...] -> obj
294 * Creates a new class, named by <i>aString</i>, containing accessor
295 * methods for the given symbols. If the name <i>aString</i> is
296 * omitted, an anonymous structure class will be created. Otherwise,
297 * the name of this struct will appear as a constant in class
298 * <code>Struct</code>, so it must be unique for all
299 * <code>Struct</code>s in the system and should start with a capital
300 * letter. Assigning a structure class to a constant effectively gives
301 * the class the name of the constant.
303 * <code>Struct::new</code> returns a new <code>Class</code> object,
304 * which can then be used to create specific instances of the new
305 * structure. The number of actual parameters must be
306 * less than or equal to the number of attributes defined for this
307 * class; unset parameters default to <code>nil</code>. Passing too many
308 * parameters will raise an <code>ArgumentError</code>.
310 * The remaining methods listed in this section (class and instance)
311 * are defined for this generated class.
313 * # Create a structure with a name in Struct
314 * Struct.new("Customer", :name, :address) #=> Struct::Customer
315 * Struct::Customer.new("Dave", "123 Main") #=> #<struct Struct::Customer name="Dave", address="123 Main">
317 * # Create a structure named by its constant
318 * Customer = Struct.new(:name, :address) #=> Customer
319 * Customer.new("Dave", "123 Main") #=> #<struct Customer name="Dave", address="123 Main">
322 mrb_struct_s_def(mrb_state
*mrb
, mrb_value klass
)
324 mrb_value name
, rest
;
333 name
= mrb_nil_value();
334 rest
= mrb_nil_value();
335 mrb_get_args(mrb
, "*&", &argv
, &argc
, &b
);
336 if (argc
== 0) { /* special case to avoid crash */
337 rest
= mrb_ary_new(mrb
);
340 if (argc
> 0) name
= argv
[0];
341 if (argc
> 1) rest
= argv
[1];
342 if (mrb_array_p(rest
)) {
343 if (!mrb_nil_p(name
) && mrb_symbol_p(name
)) {
344 /* 1stArgument:symbol -> name=nil rest=argv[0]-[n] */
345 mrb_ary_unshift(mrb
, rest
, name
);
346 name
= mrb_nil_value();
352 if (!mrb_nil_p(name
) && mrb_symbol_p(name
)) {
353 /* 1stArgument:symbol -> name=nil rest=argv[0]-[n] */
354 name
= mrb_nil_value();
358 rest
= mrb_ary_new_from_values(mrb
, argcnt
, pargv
);
360 for (i
=0; i
<RARRAY_LEN(rest
); i
++) {
361 id
= mrb_obj_to_sym(mrb
, RARRAY_PTR(rest
)[i
]);
362 RARRAY_PTR(rest
)[i
] = mrb_symbol_value(id
);
365 st
= make_struct(mrb
, name
, rest
, struct_class(mrb
));
367 mrb_yield_with_class(mrb
, b
, 1, &st
, st
, mrb_class_ptr(klass
));
374 num_members(mrb_state
*mrb
, struct RClass
*klass
)