mbed I/F binding for mruby
Dependents: mruby_mbed_web mirb_mbed
struct.c
00001 /* 00002 ** struct.c - Struct class 00003 ** 00004 ** See Copyright Notice in mruby.h 00005 */ 00006 00007 #include <ctype.h> 00008 #include <string.h> 00009 #include "mruby.h" 00010 #include "mruby/array.h" 00011 #include "mruby/string.h" 00012 #include "mruby/class.h" 00013 #include "mruby/variable.h" 00014 #include "mruby/hash.h" 00015 #include "mruby/range.h" 00016 00017 #define RSTRUCT_LEN(st) mrb_ary_ptr(st)->len 00018 #define RSTRUCT_PTR(st) mrb_ary_ptr(st)->ptr 00019 00020 static struct RClass * 00021 struct_class(mrb_state *mrb) 00022 { 00023 return mrb_class_get(mrb, "Struct"); 00024 } 00025 00026 static inline mrb_value 00027 struct_ivar_get(mrb_state *mrb, mrb_value c, mrb_sym id) 00028 { 00029 struct RClass* kclass; 00030 struct RClass* sclass = struct_class(mrb); 00031 mrb_value ans; 00032 00033 for (;;) { 00034 ans = mrb_iv_get(mrb, c, id); 00035 if (!mrb_nil_p(ans)) return ans; 00036 kclass = RCLASS_SUPER(c); 00037 if (kclass == 0 || kclass == sclass) 00038 return mrb_nil_value(); 00039 c = mrb_obj_value(kclass); 00040 } 00041 } 00042 00043 static mrb_value 00044 mrb_struct_s_members(mrb_state *mrb, mrb_value klass) 00045 { 00046 mrb_value members = struct_ivar_get(mrb, klass, mrb_intern_lit(mrb, "__members__")); 00047 00048 if (mrb_nil_p(members)) { 00049 mrb_raise(mrb, E_TYPE_ERROR, "uninitialized struct"); 00050 } 00051 if (!mrb_array_p(members)) { 00052 mrb_raise(mrb, E_TYPE_ERROR, "corrupted struct"); 00053 } 00054 return members; 00055 } 00056 00057 static mrb_value 00058 mrb_struct_members(mrb_state *mrb, mrb_value s) 00059 { 00060 mrb_value members = mrb_struct_s_members(mrb, mrb_obj_value(mrb_obj_class(mrb, s))); 00061 if (!strcmp(mrb_class_name(mrb, mrb_obj_class(mrb, s)), "Struct")) { 00062 if (RSTRUCT_LEN(s) != RARRAY_LEN(members)) { 00063 mrb_raisef(mrb, E_TYPE_ERROR, 00064 "struct size differs (%S required %S given)", 00065 mrb_fixnum_value(RARRAY_LEN(members)), mrb_fixnum_value(RSTRUCT_LEN(s))); 00066 } 00067 } 00068 return members; 00069 } 00070 00071 static mrb_value 00072 mrb_struct_s_members_m(mrb_state *mrb, mrb_value klass) 00073 { 00074 mrb_value members, ary; 00075 00076 members = mrb_struct_s_members(mrb, klass); 00077 ary = mrb_ary_new_capa(mrb, RARRAY_LEN(members)); 00078 mrb_ary_replace(mrb, ary, members); 00079 return ary; 00080 } 00081 00082 /* 15.2.18.4.6 */ 00083 /* 00084 * call-seq: 00085 * struct.members -> array 00086 * 00087 * Returns an array of strings representing the names of the instance 00088 * variables. 00089 * 00090 * Customer = Struct.new(:name, :address, :zip) 00091 * joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345) 00092 * joe.members #=> [:name, :address, :zip] 00093 */ 00094 00095 static mrb_value 00096 mrb_struct_members_m(mrb_state *mrb, mrb_value obj) 00097 { 00098 return mrb_struct_s_members_m(mrb, mrb_obj_value(mrb_obj_class(mrb, obj))); 00099 } 00100 00101 static mrb_value 00102 mrb_struct_getmember(mrb_state *mrb, mrb_value obj, mrb_sym id) 00103 { 00104 mrb_value members, slot, *ptr; 00105 const mrb_value *ptr_members; 00106 mrb_int i, len; 00107 00108 ptr = RSTRUCT_PTR(obj); 00109 members = mrb_struct_members(mrb, obj); 00110 ptr_members = RARRAY_PTR(members); 00111 slot = mrb_symbol_value(id); 00112 len = RARRAY_LEN(members); 00113 for (i=0; i<len; i++) { 00114 if (mrb_obj_equal(mrb, ptr_members[i], slot)) { 00115 return ptr[i]; 00116 } 00117 } 00118 mrb_raisef(mrb, E_INDEX_ERROR, "`%S' is not a struct member", mrb_sym2str(mrb, id)); 00119 return mrb_nil_value(); /* not reached */ 00120 } 00121 00122 static mrb_value 00123 mrb_struct_ref(mrb_state *mrb, mrb_value obj) 00124 { 00125 return mrb_struct_getmember(mrb, obj, mrb->c->ci->mid); 00126 } 00127 00128 static mrb_value mrb_struct_ref0(mrb_state* mrb, mrb_value obj) {return RSTRUCT_PTR(obj)[0];} 00129 static mrb_value mrb_struct_ref1(mrb_state* mrb, mrb_value obj) {return RSTRUCT_PTR(obj)[1];} 00130 static mrb_value mrb_struct_ref2(mrb_state* mrb, mrb_value obj) {return RSTRUCT_PTR(obj)[2];} 00131 static mrb_value mrb_struct_ref3(mrb_state* mrb, mrb_value obj) {return RSTRUCT_PTR(obj)[3];} 00132 static mrb_value mrb_struct_ref4(mrb_state* mrb, mrb_value obj) {return RSTRUCT_PTR(obj)[4];} 00133 static mrb_value mrb_struct_ref5(mrb_state* mrb, mrb_value obj) {return RSTRUCT_PTR(obj)[5];} 00134 static mrb_value mrb_struct_ref6(mrb_state* mrb, mrb_value obj) {return RSTRUCT_PTR(obj)[6];} 00135 static mrb_value mrb_struct_ref7(mrb_state* mrb, mrb_value obj) {return RSTRUCT_PTR(obj)[7];} 00136 static mrb_value mrb_struct_ref8(mrb_state* mrb, mrb_value obj) {return RSTRUCT_PTR(obj)[8];} 00137 static mrb_value mrb_struct_ref9(mrb_state* mrb, mrb_value obj) {return RSTRUCT_PTR(obj)[9];} 00138 00139 #define numberof(array) (int)(sizeof(array) / sizeof((array)[0])) 00140 #define N_REF_FUNC numberof(ref_func) 00141 00142 static const mrb_func_t ref_func[] = { 00143 mrb_struct_ref0, 00144 mrb_struct_ref1, 00145 mrb_struct_ref2, 00146 mrb_struct_ref3, 00147 mrb_struct_ref4, 00148 mrb_struct_ref5, 00149 mrb_struct_ref6, 00150 mrb_struct_ref7, 00151 mrb_struct_ref8, 00152 mrb_struct_ref9, 00153 }; 00154 00155 static mrb_sym 00156 mrb_id_attrset(mrb_state *mrb, mrb_sym id) 00157 { 00158 const char *name; 00159 char *buf; 00160 mrb_int len; 00161 mrb_sym mid; 00162 00163 name = mrb_sym2name_len(mrb, id, &len); 00164 buf = (char *)mrb_malloc(mrb, (size_t)len+2); 00165 memcpy(buf, name, (size_t)len); 00166 buf[len] = '='; 00167 buf[len+1] = '\0'; 00168 00169 mid = mrb_intern(mrb, buf, len+1); 00170 mrb_free(mrb, buf); 00171 return mid; 00172 } 00173 00174 static mrb_value 00175 mrb_struct_set(mrb_state *mrb, mrb_value obj, mrb_value val) 00176 { 00177 const char *name; 00178 mrb_int i, len, slen; 00179 mrb_sym mid; 00180 mrb_value members, slot, *ptr; 00181 const mrb_value *ptr_members; 00182 00183 /* get base id */ 00184 name = mrb_sym2name_len(mrb, mrb->c->ci->mid, &slen); 00185 mid = mrb_intern(mrb, name, slen-1); /* omit last "=" */ 00186 00187 members = mrb_struct_members(mrb, obj); 00188 ptr_members = RARRAY_PTR(members); 00189 len = RARRAY_LEN(members); 00190 ptr = RSTRUCT_PTR(obj); 00191 for (i=0; i<len; i++) { 00192 slot = ptr_members[i]; 00193 if (mrb_symbol(slot) == mid) { 00194 return ptr[i] = val; 00195 } 00196 } 00197 mrb_raisef(mrb, E_INDEX_ERROR, "`%S' is not a struct member", mrb_sym2str(mrb, mid)); 00198 return mrb_nil_value(); /* not reached */ 00199 } 00200 00201 static mrb_value 00202 mrb_struct_set_m(mrb_state *mrb, mrb_value obj) 00203 { 00204 mrb_value val; 00205 00206 mrb_get_args(mrb, "o", &val); 00207 return mrb_struct_set(mrb, obj, val); 00208 } 00209 00210 static mrb_bool 00211 is_local_id(mrb_state *mrb, const char *name) 00212 { 00213 if (!name) return FALSE; 00214 return !ISUPPER(name[0]); 00215 } 00216 00217 static mrb_bool 00218 is_const_id(mrb_state *mrb, const char *name) 00219 { 00220 if (!name) return FALSE; 00221 return ISUPPER(name[0]); 00222 } 00223 00224 static void 00225 make_struct_define_accessors(mrb_state *mrb, mrb_value members, struct RClass *c) 00226 { 00227 const mrb_value *ptr_members = RARRAY_PTR(members); 00228 mrb_int i; 00229 mrb_int len = RARRAY_LEN(members); 00230 int ai = mrb_gc_arena_save(mrb); 00231 00232 for (i=0; i<len; i++) { 00233 mrb_sym id = mrb_symbol(ptr_members[i]); 00234 const char *name = mrb_sym2name_len(mrb, id, NULL); 00235 00236 if (is_local_id(mrb, name) || is_const_id(mrb, name)) { 00237 if (i < N_REF_FUNC) { 00238 mrb_define_method_id(mrb, c, id, ref_func[i], MRB_ARGS_NONE()); 00239 } 00240 else { 00241 mrb_define_method_id(mrb, c, id, mrb_struct_ref, MRB_ARGS_NONE()); 00242 } 00243 mrb_define_method_id(mrb, c, mrb_id_attrset(mrb, id), mrb_struct_set_m, MRB_ARGS_REQ(1)); 00244 mrb_gc_arena_restore(mrb, ai); 00245 } 00246 } 00247 } 00248 00249 static mrb_value 00250 make_struct(mrb_state *mrb, mrb_value name, mrb_value members, struct RClass * klass) 00251 { 00252 mrb_value nstr; 00253 mrb_sym id; 00254 struct RClass *c; 00255 00256 if (mrb_nil_p(name)) { 00257 c = mrb_class_new(mrb, klass); 00258 } 00259 else { 00260 /* old style: should we warn? */ 00261 name = mrb_str_to_str(mrb, name); 00262 id = mrb_obj_to_sym(mrb, name); 00263 if (!is_const_id(mrb, mrb_sym2name_len(mrb, id, NULL))) { 00264 mrb_name_error(mrb, id, "identifier %S needs to be constant", name); 00265 } 00266 if (mrb_const_defined_at(mrb, mrb_obj_value(klass), id)) { 00267 mrb_warn(mrb, "redefining constant Struct::%S", name); 00268 /* ?rb_mod_remove_const(klass, mrb_sym2name(mrb, id)); */ 00269 } 00270 c = mrb_define_class_under(mrb, klass, RSTRING_PTR(name), klass); 00271 } 00272 MRB_SET_INSTANCE_TT(c, MRB_TT_ARRAY); 00273 nstr = mrb_obj_value(c); 00274 mrb_iv_set(mrb, nstr, mrb_intern_lit(mrb, "__members__"), members); 00275 00276 mrb_define_class_method(mrb, c, "new", mrb_instance_new, MRB_ARGS_ANY()); 00277 mrb_define_class_method(mrb, c, "[]", mrb_instance_new, MRB_ARGS_ANY()); 00278 mrb_define_class_method(mrb, c, "members", mrb_struct_s_members_m, MRB_ARGS_NONE()); 00279 /* RSTRUCT(nstr)->basic.c->super = c->c; */ 00280 make_struct_define_accessors(mrb, members, c); 00281 return nstr; 00282 } 00283 00284 /* 15.2.18.3.1 */ 00285 /* 00286 * call-seq: 00287 * Struct.new( [aString] [, aSym]+> ) -> StructClass 00288 * StructClass.new(arg, ...) -> obj 00289 * StructClass[arg, ...] -> obj 00290 * 00291 * Creates a new class, named by <i>aString</i>, containing accessor 00292 * methods for the given symbols. If the name <i>aString</i> is 00293 * omitted, an anonymous structure class will be created. Otherwise, 00294 * the name of this struct will appear as a constant in class 00295 * <code>Struct</code>, so it must be unique for all 00296 * <code>Struct</code>s in the system and should start with a capital 00297 * letter. Assigning a structure class to a constant effectively gives 00298 * the class the name of the constant. 00299 * 00300 * <code>Struct::new</code> returns a new <code>Class</code> object, 00301 * which can then be used to create specific instances of the new 00302 * structure. The number of actual parameters must be 00303 * less than or equal to the number of attributes defined for this 00304 * class; unset parameters default to <code>nil</code>. Passing too many 00305 * parameters will raise an <code>ArgumentError</code>. 00306 * 00307 * The remaining methods listed in this section (class and instance) 00308 * are defined for this generated class. 00309 * 00310 * # Create a structure with a name in Struct 00311 * Struct.new("Customer", :name, :address) #=> Struct::Customer 00312 * Struct::Customer.new("Dave", "123 Main") #=> #<struct Struct::Customer name="Dave", address="123 Main"> 00313 * 00314 * # Create a structure named by its constant 00315 * Customer = Struct.new(:name, :address) #=> Customer 00316 * Customer.new("Dave", "123 Main") #=> #<struct Customer name="Dave", address="123 Main"> 00317 */ 00318 static mrb_value 00319 mrb_struct_s_def(mrb_state *mrb, mrb_value klass) 00320 { 00321 mrb_value name, rest; 00322 mrb_value *pargv; 00323 mrb_int argcnt; 00324 mrb_int i; 00325 mrb_value b, st; 00326 mrb_sym id; 00327 mrb_value *argv; 00328 mrb_int argc; 00329 00330 name = mrb_nil_value(); 00331 rest = mrb_nil_value(); 00332 mrb_get_args(mrb, "*&", &argv, &argc, &b); 00333 if (argc == 0) { /* special case to avoid crash */ 00334 rest = mrb_ary_new(mrb); 00335 } 00336 else { 00337 if (argc > 0) name = argv[0]; 00338 if (argc > 1) rest = argv[1]; 00339 if (mrb_array_p(rest)) { 00340 if (!mrb_nil_p(name) && mrb_symbol_p(name)) { 00341 /* 1stArgument:symbol -> name=nil rest=argv[0]-[n] */ 00342 mrb_ary_unshift(mrb, rest, name); 00343 name = mrb_nil_value(); 00344 } 00345 } 00346 else { 00347 pargv = &argv[1]; 00348 argcnt = argc-1; 00349 if (!mrb_nil_p(name) && mrb_symbol_p(name)) { 00350 /* 1stArgument:symbol -> name=nil rest=argv[0]-[n] */ 00351 name = mrb_nil_value(); 00352 pargv = &argv[0]; 00353 argcnt++; 00354 } 00355 rest = mrb_ary_new_from_values(mrb, argcnt, pargv); 00356 } 00357 for (i=0; i<RARRAY_LEN(rest); i++) { 00358 id = mrb_obj_to_sym(mrb, RARRAY_PTR(rest)[i]); 00359 mrb_ary_set(mrb, rest, i, mrb_symbol_value(id)); 00360 } 00361 } 00362 st = make_struct(mrb, name, rest, struct_class(mrb)); 00363 if (!mrb_nil_p(b)) { 00364 mrb_yield_with_class(mrb, b, 1, &st, st, mrb_class_ptr(klass)); 00365 } 00366 00367 return st; 00368 } 00369 00370 static mrb_int 00371 num_members(mrb_state *mrb, struct RClass *klass) 00372 { 00373 mrb_value members; 00374 00375 members = struct_ivar_get(mrb, mrb_obj_value(klass), mrb_intern_lit(mrb, "__members__")); 00376 if (!mrb_array_p(members)) { 00377 mrb_raise(mrb, E_TYPE_ERROR, "broken members"); 00378 } 00379 return RARRAY_LEN(members); 00380 } 00381 00382 /* 15.2.18.4.8 */ 00383 /* 00384 */ 00385 static mrb_value 00386 mrb_struct_initialize_withArg(mrb_state *mrb, mrb_int argc, mrb_value *argv, mrb_value self) 00387 { 00388 struct RClass *klass = mrb_obj_class(mrb, self); 00389 mrb_int i, n; 00390 00391 n = num_members(mrb, klass); 00392 if (n < argc) { 00393 mrb_raise(mrb, E_ARGUMENT_ERROR, "struct size differs"); 00394 } 00395 00396 for (i = 0; i < argc; i++) { 00397 mrb_ary_set(mrb, self, i, argv[i]); 00398 } 00399 for (i = argc; i < n; i++) { 00400 mrb_ary_set(mrb, self, i, mrb_nil_value()); 00401 } 00402 return self; 00403 } 00404 00405 static mrb_value 00406 mrb_struct_initialize_m(mrb_state *mrb, /*int argc, mrb_value *argv,*/ mrb_value self) 00407 { 00408 mrb_value *argv; 00409 mrb_int argc; 00410 00411 mrb_get_args(mrb, "*", &argv, &argc); 00412 return mrb_struct_initialize_withArg(mrb, argc, argv, self); 00413 } 00414 00415 static mrb_value 00416 inspect_struct(mrb_state *mrb, mrb_value s, mrb_bool recur) 00417 { 00418 const char *cn = mrb_class_name(mrb, mrb_obj_class(mrb, s)); 00419 mrb_value members, str = mrb_str_new_lit(mrb, "#<struct "); 00420 mrb_value *ptr; 00421 const mrb_value *ptr_members; 00422 mrb_int i, len; 00423 00424 if (cn) { 00425 mrb_str_append(mrb, str, mrb_str_new_cstr(mrb, cn)); 00426 } 00427 if (recur) { 00428 return mrb_str_cat_lit(mrb, str, ":...>"); 00429 } 00430 00431 members = mrb_struct_members(mrb, s); 00432 ptr_members = RARRAY_PTR(members); 00433 ptr = RSTRUCT_PTR(s); 00434 len = RSTRUCT_LEN(s); 00435 for (i=0; i<len; i++) { 00436 mrb_value slot; 00437 mrb_sym id; 00438 const char *name; 00439 mrb_int namelen; 00440 00441 if (i > 0) { 00442 mrb_str_cat_lit(mrb, str, ", "); 00443 } 00444 else if (cn) { 00445 mrb_str_cat_lit(mrb, str, " "); 00446 } 00447 slot = ptr_members[i]; 00448 id = mrb_symbol(slot); 00449 name = mrb_sym2name_len(mrb, id, &namelen); 00450 if (is_local_id(mrb, name) || is_const_id(mrb, name)) { 00451 mrb_str_append(mrb, str, mrb_str_new(mrb, name, namelen)); 00452 } 00453 else { 00454 mrb_str_append(mrb, str, mrb_inspect(mrb, slot)); 00455 } 00456 mrb_str_cat_lit(mrb, str, "="); 00457 mrb_str_append(mrb, str, mrb_inspect(mrb, ptr[i])); 00458 } 00459 mrb_str_cat_lit(mrb, str, ">"); 00460 00461 return str; 00462 } 00463 00464 /* 00465 * call-seq: 00466 * struct.to_s -> string 00467 * struct.inspect -> string 00468 * 00469 * Describe the contents of this struct in a string. 00470 */ 00471 static mrb_value 00472 mrb_struct_inspect(mrb_state *mrb, mrb_value s) 00473 { 00474 return inspect_struct(mrb, s, FALSE); 00475 } 00476 00477 /* 15.2.18.4.9 */ 00478 /* :nodoc: */ 00479 static mrb_value 00480 mrb_struct_init_copy(mrb_state *mrb, mrb_value copy) 00481 { 00482 mrb_value s; 00483 mrb_int i, len; 00484 00485 mrb_get_args(mrb, "o", &s); 00486 00487 if (mrb_obj_equal(mrb, copy, s)) return copy; 00488 if (!mrb_obj_is_instance_of(mrb, s, mrb_obj_class(mrb, copy))) { 00489 mrb_raise(mrb, E_TYPE_ERROR, "wrong argument class"); 00490 } 00491 if (!mrb_array_p(s)) { 00492 mrb_raise(mrb, E_TYPE_ERROR, "corrupted struct"); 00493 } 00494 if (RSTRUCT_LEN(copy) != RSTRUCT_LEN(s)) { 00495 mrb_raise(mrb, E_TYPE_ERROR, "struct size mismatch"); 00496 } 00497 len = RSTRUCT_LEN(copy); 00498 for (i = 0; i < len; i++) { 00499 mrb_ary_set(mrb, copy, i, RSTRUCT_PTR(s)[i]); 00500 } 00501 return copy; 00502 } 00503 00504 static mrb_value 00505 struct_aref_sym(mrb_state *mrb, mrb_value s, mrb_sym id) 00506 { 00507 mrb_value *ptr, members; 00508 const mrb_value *ptr_members; 00509 mrb_int i, len; 00510 00511 ptr = RSTRUCT_PTR(s); 00512 members = mrb_struct_members(mrb, s); 00513 ptr_members = RARRAY_PTR(members); 00514 len = RARRAY_LEN(members); 00515 for (i=0; i<len; i++) { 00516 if (mrb_symbol(ptr_members[i]) == id) { 00517 return ptr[i]; 00518 } 00519 } 00520 mrb_raisef(mrb, E_INDEX_ERROR, "no member '%S' in struct", mrb_sym2str(mrb, id)); 00521 return mrb_nil_value(); /* not reached */ 00522 } 00523 00524 static mrb_value 00525 struct_aref_int(mrb_state *mrb, mrb_value s, mrb_int i) 00526 { 00527 if (i < 0) i = RSTRUCT_LEN(s) + i; 00528 if (i < 0) 00529 mrb_raisef(mrb, E_INDEX_ERROR, 00530 "offset %S too small for struct(size:%S)", 00531 mrb_fixnum_value(i), mrb_fixnum_value(RSTRUCT_LEN(s))); 00532 if (RSTRUCT_LEN(s) <= i) 00533 mrb_raisef(mrb, E_INDEX_ERROR, 00534 "offset %S too large for struct(size:%S)", 00535 mrb_fixnum_value(i), mrb_fixnum_value(RSTRUCT_LEN(s))); 00536 return RSTRUCT_PTR(s)[i]; 00537 } 00538 00539 /* 15.2.18.4.2 */ 00540 /* 00541 * call-seq: 00542 * struct[symbol] -> anObject 00543 * struct[fixnum] -> anObject 00544 * 00545 * Attribute Reference---Returns the value of the instance variable 00546 * named by <i>symbol</i>, or indexed (0..length-1) by 00547 * <i>fixnum</i>. Will raise <code>NameError</code> if the named 00548 * variable does not exist, or <code>IndexError</code> if the index is 00549 * out of range. 00550 * 00551 * Customer = Struct.new(:name, :address, :zip) 00552 * joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345) 00553 * 00554 * joe["name"] #=> "Joe Smith" 00555 * joe[:name] #=> "Joe Smith" 00556 * joe[0] #=> "Joe Smith" 00557 */ 00558 static mrb_value 00559 mrb_struct_aref(mrb_state *mrb, mrb_value s) 00560 { 00561 mrb_value idx; 00562 00563 mrb_get_args(mrb, "o", &idx); 00564 if (mrb_string_p(idx)) { 00565 mrb_value sym = mrb_check_intern_str(mrb, idx); 00566 00567 if (mrb_nil_p(sym)) { 00568 mrb_raisef(mrb, E_INDEX_ERROR, "no member '%S' in struct", idx); 00569 } 00570 idx = sym; 00571 } 00572 if (mrb_symbol_p(idx)) { 00573 return struct_aref_sym(mrb, s, mrb_symbol(idx)); 00574 } 00575 return struct_aref_int(mrb, s, mrb_int(mrb, idx)); 00576 } 00577 00578 static mrb_value 00579 mrb_struct_aset_sym(mrb_state *mrb, mrb_value s, mrb_sym id, mrb_value val) 00580 { 00581 mrb_value members, *ptr; 00582 const mrb_value *ptr_members; 00583 mrb_int i, len; 00584 00585 members = mrb_struct_members(mrb, s); 00586 len = RARRAY_LEN(members); 00587 if (RSTRUCT_LEN(s) != len) { 00588 mrb_raisef(mrb, E_TYPE_ERROR, 00589 "struct size differs (%S required %S given)", 00590 mrb_fixnum_value(len), mrb_fixnum_value(RSTRUCT_LEN(s))); 00591 } 00592 ptr = RSTRUCT_PTR(s); 00593 ptr_members = RARRAY_PTR(members); 00594 for (i=0; i<len; i++) { 00595 if (mrb_symbol(ptr_members[i]) == id) { 00596 ptr[i] = val; 00597 return val; 00598 } 00599 } 00600 mrb_raisef(mrb, E_INDEX_ERROR, "no member '%S' in struct", mrb_sym2str(mrb, id)); 00601 return val; /* not reach */ 00602 } 00603 00604 /* 15.2.18.4.3 */ 00605 /* 00606 * call-seq: 00607 * struct[symbol] = obj -> obj 00608 * struct[fixnum] = obj -> obj 00609 * 00610 * Attribute Assignment---Assigns to the instance variable named by 00611 * <i>symbol</i> or <i>fixnum</i> the value <i>obj</i> and 00612 * returns it. Will raise a <code>NameError</code> if the named 00613 * variable does not exist, or an <code>IndexError</code> if the index 00614 * is out of range. 00615 * 00616 * Customer = Struct.new(:name, :address, :zip) 00617 * joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345) 00618 * 00619 * joe["name"] = "Luke" 00620 * joe[:zip] = "90210" 00621 * 00622 * joe.name #=> "Luke" 00623 * joe.zip #=> "90210" 00624 */ 00625 00626 static mrb_value 00627 mrb_struct_aset(mrb_state *mrb, mrb_value s) 00628 { 00629 mrb_int i; 00630 mrb_value idx; 00631 mrb_value val; 00632 00633 mrb_get_args(mrb, "oo", &idx, &val); 00634 00635 if (mrb_string_p(idx)) { 00636 mrb_value sym = mrb_check_intern_str(mrb, idx); 00637 00638 if (mrb_nil_p(sym)) { 00639 mrb_raisef(mrb, E_INDEX_ERROR, "no member '%S' in struct", idx); 00640 } 00641 idx = sym; 00642 } 00643 if (mrb_symbol_p(idx)) { 00644 return mrb_struct_aset_sym(mrb, s, mrb_symbol(idx), val); 00645 } 00646 00647 i = mrb_int(mrb, idx); 00648 if (i < 0) i = RSTRUCT_LEN(s) + i; 00649 if (i < 0) { 00650 mrb_raisef(mrb, E_INDEX_ERROR, 00651 "offset %S too small for struct(size:%S)", 00652 mrb_fixnum_value(i), mrb_fixnum_value(RSTRUCT_LEN(s))); 00653 } 00654 if (RSTRUCT_LEN(s) <= i) { 00655 mrb_raisef(mrb, E_INDEX_ERROR, 00656 "offset %S too large for struct(size:%S)", 00657 mrb_fixnum_value(i), mrb_fixnum_value(RSTRUCT_LEN(s))); 00658 } 00659 return RSTRUCT_PTR(s)[i] = val; 00660 } 00661 00662 /* 15.2.18.4.1 */ 00663 /* 00664 * call-seq: 00665 * struct == other_struct -> true or false 00666 * 00667 * Equality---Returns <code>true</code> if <i>other_struct</i> is 00668 * equal to this one: they must be of the same class as generated by 00669 * <code>Struct::new</code>, and the values of all instance variables 00670 * must be equal (according to <code>Object#==</code>). 00671 * 00672 * Customer = Struct.new(:name, :address, :zip) 00673 * joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345) 00674 * joejr = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345) 00675 * jane = Customer.new("Jane Doe", "456 Elm, Anytown NC", 12345) 00676 * joe == joejr #=> true 00677 * joe == jane #=> false 00678 */ 00679 00680 static mrb_value 00681 mrb_struct_equal(mrb_state *mrb, mrb_value s) 00682 { 00683 mrb_value s2; 00684 mrb_value *ptr, *ptr2; 00685 mrb_int i, len; 00686 mrb_bool equal_p; 00687 00688 mrb_get_args(mrb, "o", &s2); 00689 if (mrb_obj_equal(mrb, s, s2)) { 00690 equal_p = 1; 00691 } 00692 else if (!strcmp(mrb_class_name(mrb, mrb_obj_class(mrb, s)), "Struct") || 00693 mrb_obj_class(mrb, s) != mrb_obj_class(mrb, s2)) { 00694 equal_p = 0; 00695 } 00696 else if (RSTRUCT_LEN(s) != RSTRUCT_LEN(s2)) { 00697 mrb_bug(mrb, "inconsistent struct"); /* should never happen */ 00698 equal_p = 0; /* This substuture is just to suppress warnings. never called. */ 00699 } 00700 else { 00701 ptr = RSTRUCT_PTR(s); 00702 ptr2 = RSTRUCT_PTR(s2); 00703 len = RSTRUCT_LEN(s); 00704 equal_p = 1; 00705 for (i=0; i<len; i++) { 00706 if (!mrb_equal(mrb, ptr[i], ptr2[i])) { 00707 equal_p = 0; 00708 break; 00709 } 00710 } 00711 } 00712 00713 return mrb_bool_value(equal_p); 00714 } 00715 00716 /* 15.2.18.4.12(x) */ 00717 /* 00718 * code-seq: 00719 * struct.eql?(other) -> true or false 00720 * 00721 * Two structures are equal if they are the same object, or if all their 00722 * fields are equal (using <code>eql?</code>). 00723 */ 00724 static mrb_value 00725 mrb_struct_eql(mrb_state *mrb, mrb_value s) 00726 { 00727 mrb_value s2; 00728 mrb_value *ptr, *ptr2; 00729 mrb_int i, len; 00730 mrb_bool eql_p; 00731 00732 mrb_get_args(mrb, "o", &s2); 00733 if (mrb_obj_equal(mrb, s, s2)) { 00734 eql_p = 1; 00735 } 00736 else if (strcmp(mrb_class_name(mrb, mrb_obj_class(mrb, s2)), "Struct") || 00737 mrb_obj_class(mrb, s) != mrb_obj_class(mrb, s2)) { 00738 eql_p = 0; 00739 } 00740 else if (RSTRUCT_LEN(s) != RSTRUCT_LEN(s2)) { 00741 mrb_bug(mrb, "inconsistent struct"); /* should never happen */ 00742 eql_p = 0; /* This substuture is just to suppress warnings. never called. */ 00743 } 00744 else { 00745 ptr = RSTRUCT_PTR(s); 00746 ptr2 = RSTRUCT_PTR(s2); 00747 len = RSTRUCT_LEN(s); 00748 eql_p = 1; 00749 for (i=0; i<len; i++) { 00750 if (!mrb_eql(mrb, ptr[i], ptr2[i])) { 00751 eql_p = 0; 00752 break; 00753 } 00754 } 00755 } 00756 00757 return mrb_bool_value(eql_p); 00758 } 00759 00760 /* 00761 * call-seq: 00762 * struct.length -> Fixnum 00763 * struct.size -> Fixnum 00764 * 00765 * Returns number of struct members. 00766 */ 00767 static mrb_value 00768 mrb_struct_len(mrb_state *mrb, mrb_value self) 00769 { 00770 return mrb_fixnum_value(RSTRUCT_LEN(self)); 00771 } 00772 00773 /* 00774 * call-seq: 00775 * struct.to_a -> array 00776 * struct.values -> array 00777 * 00778 * Create an array from struct values. 00779 */ 00780 static mrb_value 00781 mrb_struct_to_a(mrb_state *mrb, mrb_value self) 00782 { 00783 return mrb_ary_new_from_values(mrb, RSTRUCT_LEN(self), RSTRUCT_PTR(self)); 00784 } 00785 00786 /* 00787 * call-seq: 00788 * struct.to_h -> hash 00789 * 00790 * Create a hash from member names and struct values. 00791 */ 00792 static mrb_value 00793 mrb_struct_to_h(mrb_state *mrb, mrb_value self) 00794 { 00795 mrb_value members, ret; 00796 mrb_int i; 00797 00798 members = mrb_struct_s_members(mrb, mrb_obj_value(mrb_class(mrb, self))); 00799 ret = mrb_hash_new_capa(mrb, RARRAY_LEN(members)); 00800 00801 for (i = 0; i < RARRAY_LEN(members); ++i) { 00802 mrb_hash_set(mrb, ret, RARRAY_PTR(members)[i], RSTRUCT_PTR(self)[i]); 00803 } 00804 00805 return ret; 00806 } 00807 00808 static mrb_value 00809 mrb_struct_values_at(mrb_state *mrb, mrb_value self) 00810 { 00811 mrb_int argc; 00812 mrb_value *argv; 00813 00814 mrb_get_args(mrb, "*", &argv, &argc); 00815 00816 return mrb_get_values_at(mrb, self, RSTRUCT_LEN(self), argc, argv, struct_aref_int); 00817 } 00818 00819 /* 00820 * A <code>Struct</code> is a convenient way to bundle a number of 00821 * attributes together, using accessor methods, without having to write 00822 * an explicit class. 00823 * 00824 * The <code>Struct</code> class is a generator of specific classes, 00825 * each one of which is defined to hold a set of variables and their 00826 * accessors. In these examples, we'll call the generated class 00827 * ``<i>Customer</i>Class,'' and we'll show an example instance of that 00828 * class as ``<i>Customer</i>Inst.'' 00829 * 00830 * In the descriptions that follow, the parameter <i>symbol</i> refers 00831 * to a symbol, which is either a quoted string or a 00832 * <code>Symbol</code> (such as <code>:name</code>). 00833 */ 00834 void 00835 mrb_mruby_struct_gem_init(mrb_state* mrb) 00836 { 00837 struct RClass *st; 00838 st = mrb_define_class(mrb, "Struct", mrb->object_class); 00839 00840 mrb_define_class_method(mrb, st, "new", mrb_struct_s_def, MRB_ARGS_ANY()); /* 15.2.18.3.1 */ 00841 00842 mrb_define_method(mrb, st, "==", mrb_struct_equal, MRB_ARGS_REQ(1)); /* 15.2.18.4.1 */ 00843 mrb_define_method(mrb, st, "[]", mrb_struct_aref, MRB_ARGS_REQ(1)); /* 15.2.18.4.2 */ 00844 mrb_define_method(mrb, st, "[]=", mrb_struct_aset, MRB_ARGS_REQ(2)); /* 15.2.18.4.3 */ 00845 mrb_define_method(mrb, st, "members", mrb_struct_members_m, MRB_ARGS_NONE()); /* 15.2.18.4.6 */ 00846 mrb_define_method(mrb, st, "initialize", mrb_struct_initialize_m,MRB_ARGS_ANY()); /* 15.2.18.4.8 */ 00847 mrb_define_method(mrb, st, "initialize_copy", mrb_struct_init_copy, MRB_ARGS_REQ(1)); /* 15.2.18.4.9 */ 00848 mrb_define_method(mrb, st, "inspect", mrb_struct_inspect, MRB_ARGS_NONE()); /* 15.2.18.4.10(x) */ 00849 mrb_define_alias(mrb, st, "to_s", "inspect"); /* 15.2.18.4.11(x) */ 00850 mrb_define_method(mrb, st, "eql?", mrb_struct_eql, MRB_ARGS_REQ(1)); /* 15.2.18.4.12(x) */ 00851 00852 mrb_define_method(mrb, st, "size", mrb_struct_len, MRB_ARGS_NONE()); 00853 mrb_define_method(mrb, st, "length", mrb_struct_len, MRB_ARGS_NONE()); 00854 mrb_define_method(mrb, st, "to_a", mrb_struct_to_a, MRB_ARGS_NONE()); 00855 mrb_define_method(mrb, st, "values", mrb_struct_to_a, MRB_ARGS_NONE()); 00856 mrb_define_method(mrb, st, "to_h", mrb_struct_to_h, MRB_ARGS_NONE()); 00857 mrb_define_method(mrb, st, "values_at", mrb_struct_values_at, MRB_ARGS_NONE()); 00858 } 00859 00860 void 00861 mrb_mruby_struct_gem_final(mrb_state* mrb) 00862 { 00863 } 00864
Generated on Tue Jul 12 2022 18:00:35 by 1.7.2