diff options
| -rw-r--r-- | include/mruby/string.h | 215 | ||||
| -rw-r--r-- | mrbgems/mruby-compiler/core/codegen.c | 6 | ||||
| -rw-r--r-- | mrbgems/mruby-struct/src/struct.c | 122 | ||||
| -rw-r--r-- | mrbgems/mruby-struct/test/struct.rb | 3 |
4 files changed, 247 insertions, 99 deletions
diff --git a/include/mruby/string.h b/include/mruby/string.h index b94c355fe..b66bc0dd1 100644 --- a/include/mruby/string.h +++ b/include/mruby/string.h @@ -88,35 +88,215 @@ mrb_int mrb_str_strlen(mrb_state*, struct RString*); void mrb_gc_free_str(mrb_state*, struct RString*); MRB_API void mrb_str_modify(mrb_state*, struct RString*); +/* + * Appends self to other. Returns self as a concatnated string. + * + * + * Example: + * + * !!!c + * int + * main(int argc, + * char **argv) + * { + * // Variable declarations. + * mrb_value str1; + * mrb_value str2; + * + * mrb_state *mrb = mrb_open(); + * if (!mrb) + * { + * // handle error + * } + * + * // Creates new Ruby strings. + * str1 = mrb_str_new_cstr(mrb, "abc"); + * str2 = mrb_str_new_cstr(mrb, "def"); + * + * // Concatnates str2 to str1. + * mrb_str_concat(mrb, str1, str2); + * + * // Prints new Concatnated Ruby string. + * mrb_p(mrb, str1); + * + * mrb_close(mrb); + * return 0; + * } + * + * + * Result: + * + * => "abcdef" + * + * @param [mrb_state] mrb The current mruby state. + * @param [mrb_value] self String to concatenate. + * @param [mrb_value] other String to append to self. + * @return [mrb_value] Returns a new String appending other to self. + */ MRB_API void mrb_str_concat(mrb_state*, mrb_value, mrb_value); /* * Adds two strings together. + * + * + * Example: + * + * !!!c + * int + * main(int argc, + * char **argv) + * { + * // Variable declarations. + * mrb_value a; + * mrb_value b; + * mrb_value c; + * + * mrb_state *mrb = mrb_open(); + * if (!mrb) + * { + * // handle error + * } + * + * // Creates two Ruby strings from the passed in C strings. + * a = mrb_str_new_cstr(mrb, "abc"); + * b = mrb_str_new_cstr(mrb, "def"); + * + * // Prints both C strings. + * mrb_p(mrb, a); + * mrb_p(mrb, b); + * + * // Concatnates both Ruby strings. + * c = mrb_str_plus(mrb, a, b); + * + * // Prints new Concatnated Ruby string. + * mrb_p(mrb, c); + * + * mrb_close(mrb); + * return 0; + * } + * + * + * Result: + * + * => "abc" # First string + * => "def" # Second string + * => "abcdef" # First & Second concatnated. + * + * @param [mrb_state] mrb The current mruby state. + * @param [mrb_value] a First string to concatenate. + * @param [mrb_value] b Second string to concatenate. + * @return [mrb_value] Returns a new String containing a concatenated to b. */ MRB_API mrb_value mrb_str_plus(mrb_state*, mrb_value, mrb_value); /* * Converts pointer into a Ruby string. + * + * @param [mrb_state] mrb The current mruby state. + * @param [void*] p The pointer to convert to Ruby string. + * @return [mrb_value] Returns a new Ruby String. */ MRB_API mrb_value mrb_ptr_to_str(mrb_state *, void*); /* * Returns an object as a Ruby string. + * + * @param [mrb_state] mrb The current mruby state. + * @param [mrb_value] obj An object to return as a Ruby string. + * @return [mrb_value] An object as a Ruby string. */ MRB_API mrb_value mrb_obj_as_string(mrb_state *mrb, mrb_value obj); /* - * Resizes the string's length. + * Resizes the string's length. Returns the amount of characters + * in the specified by len. + * + * Example: + * + * !!!c + * int + * main(int argc, + * char **argv) + * { + * // Variable declaration. + * mrb_value str; + * + * mrb_state *mrb = mrb_open(); + * if (!mrb) + * { + * // handle error + * } + * // Creates a new string. + * str = mrb_str_new_cstr(mrb, "Hello, world!"); + * // Returns 5 characters of + * mrb_str_resize(mrb, str, 5); + * mrb_p(mrb, str); + * + * mrb_close(mrb); + * return 0; + * } + * + * Result: + * + * => "Hello" + * + * @param [mrb_state] mrb The current mruby state. + * @param [mrb_value] str The Ruby string to resize. + * @param [mrb_value] len The length. + * @return [mrb_value] An object as a Ruby string. */ MRB_API mrb_value mrb_str_resize(mrb_state *mrb, mrb_value str, mrb_int len); /* * Returns a sub string. + * + * Example: + * + * !!!c + * int + * main(int argc, + * char const **argv) + * { + * // Variable declarations. + * mrb_value str1; + * mrb_value str2; + * + * mrb_state *mrb = mrb_open(); + * if (!mrb) + * { + * // handle error + * } + * // Creates new string. + * str1 = mrb_str_new_cstr(mrb, "Hello, world!"); + * // Returns a sub-string within the range of 0..2 + * str2 = mrb_str_substr(mrb, str1, 0, 2); + * + * // Prints sub-string. + * mrb_p(mrb, str2); + * + * mrb_close(mrb); + * return 0; + * } + * + * Result: + * + * => "He" + * + * @param [mrb_state] mrb The current mruby state. + * @param [mrb_value] str Ruby string. + * @param [mrb_int] beg The beginning point of the sub-string. + * @param [mrb_int] len The end point of the sub-string. + * @return [mrb_value] An object as a Ruby sub-string. */ MRB_API mrb_value mrb_str_substr(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len); /* * Returns a Ruby string type. + * + * + * @param [mrb_state] mrb The current mruby state. + * @param [mrb_value] str Ruby string. + * @return [mrb_value] A Ruby string. */ MRB_API mrb_value mrb_string_type(mrb_state *mrb, mrb_value str); @@ -125,15 +305,32 @@ MRB_API mrb_value mrb_str_buf_new(mrb_state *mrb, size_t capa); MRB_API const char *mrb_string_value_cstr(mrb_state *mrb, mrb_value *ptr); MRB_API const char *mrb_string_value_ptr(mrb_state *mrb, mrb_value str); +/* + * Returns the length of the Ruby string. + * + * + * @param [mrb_state] mrb The current mruby state. + * @param [mrb_value] str Ruby string. + * @return [mrb_int] The length of the passed in Ruby string. + */ MRB_API mrb_int mrb_string_value_len(mrb_state *mrb, mrb_value str); /* * Duplicates a string object. + * + * + * @param [mrb_state] mrb The current mruby state. + * @param [mrb_value] str Ruby string. + * @return [mrb_value] Duplicated Ruby string. */ MRB_API mrb_value mrb_str_dup(mrb_state *mrb, mrb_value str); /* - * Returns a symbol from a passed in string. + * Returns a symbol from a passed in Ruby string. + * + * @param [mrb_state] mrb The current mruby state. + * @param [mrb_value] self Ruby string. + * @return [mrb_value] A symbol. */ MRB_API mrb_value mrb_str_intern(mrb_state *mrb, mrb_value self); @@ -147,12 +344,22 @@ MRB_API mrb_value mrb_str_to_str(mrb_state *mrb, mrb_value str); /* * Returns true if the strings match and false if the strings don't match. + * + * @param [mrb_state] mrb The current mruby state. + * @param [mrb_value] str1 Ruby string to compare. + * @param [mrb_value] str2 Ruby string to compare. + * @return [mrb_value] boolean value. */ MRB_API mrb_bool mrb_str_equal(mrb_state *mrb, mrb_value str1, mrb_value str2); /* * Returns a concated string comprised of a Ruby string and a C string. * + * @param [mrb_state] mrb The current mruby state. + * @param [mrb_value] str Ruby string. + * @param [const char *] ptr A C string. + * @param [size_t] len length of C string. + * @return [mrb_value] A Ruby string. * @see mrb_str_cat_cstr */ MRB_API mrb_value mrb_str_cat(mrb_state *mrb, mrb_value str, const char *ptr, size_t len); @@ -160,6 +367,10 @@ MRB_API mrb_value mrb_str_cat(mrb_state *mrb, mrb_value str, const char *ptr, si /* * Returns a concated string comprised of a Ruby string and a C string. * + * @param [mrb_state] mrb The current mruby state. + * @param [mrb_value] str Ruby string. + * @param [const char *] ptr A C string. + * @return [mrb_value] A Ruby string. * @see mrb_str_cat */ MRB_API mrb_value mrb_str_cat_cstr(mrb_state *mrb, mrb_value str, const char *ptr); diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c index dde289e7c..6e9c3c147 100644 --- a/mrbgems/mruby-compiler/core/codegen.c +++ b/mrbgems/mruby-compiler/core/codegen.c @@ -1785,7 +1785,7 @@ codegen(codegen_scope *s, node *tree, int val) int pos; pop(); - if (val) { + if (val && vsp >= 0) { genop(s, MKOP_AB(OP_MOVE, vsp, cursp())); pos = genop(s, MKOP_AsBx(name[0]=='|'?OP_JMPIF:OP_JMPNOT, cursp(), 0)); } @@ -1794,7 +1794,7 @@ codegen(codegen_scope *s, node *tree, int val) } codegen(s, tree->cdr->cdr->car, VAL); pop(); - if (val) { + if (val && vsp >= 0) { genop(s, MKOP_AB(OP_MOVE, vsp, cursp())); } if ((intptr_t)tree->car->car == NODE_CALL) { @@ -1855,7 +1855,7 @@ codegen(codegen_scope *s, node *tree, int val) gen_assignment(s, tree->car, cursp(), val); } else { - if (val) { + if (val && vsp >= 0) { genop(s, MKOP_AB(OP_MOVE, vsp, cursp())); } if (callargs == CALL_MAXARGS) { diff --git a/mrbgems/mruby-struct/src/struct.c b/mrbgems/mruby-struct/src/struct.c index f084e4031..1a06e0c12 100644 --- a/mrbgems/mruby-struct/src/struct.c +++ b/mrbgems/mruby-struct/src/struct.c @@ -61,9 +61,14 @@ struct_members(mrb_state *mrb, mrb_value s) mrb_raise(mrb, E_TYPE_ERROR, "corrupted struct"); } if (RSTRUCT_LEN(s) != RARRAY_LEN(members)) { - mrb_raisef(mrb, E_TYPE_ERROR, - "struct size differs (%S required %S given)", - mrb_fixnum_value(RARRAY_LEN(members)), mrb_fixnum_value(RSTRUCT_LEN(s))); + if (RSTRUCT_LEN(s) == 0) { /* probably uninitialized */ + mrb_ary_resize(mrb, s, RARRAY_LEN(members)); + } + else { + mrb_raisef(mrb, E_TYPE_ERROR, + "struct size differs (%S required %S given)", + mrb_fixnum_value(RARRAY_LEN(members)), mrb_fixnum_value(RSTRUCT_LEN(s))); + } } return members; } @@ -98,60 +103,14 @@ mrb_struct_members(mrb_state *mrb, mrb_value obj) return mrb_struct_s_members_m(mrb, mrb_obj_value(mrb_obj_class(mrb, obj))); } -static mrb_value -mrb_struct_getmember(mrb_state *mrb, mrb_value obj, mrb_sym id) -{ - mrb_value members, slot, *ptr; - const mrb_value *ptr_members; - mrb_int i, len; - - ptr = RSTRUCT_PTR(obj); - members = struct_members(mrb, obj); - ptr_members = RARRAY_PTR(members); - slot = mrb_symbol_value(id); - len = RARRAY_LEN(members); - for (i=0; i<len; i++) { - if (mrb_obj_equal(mrb, ptr_members[i], slot)) { - return ptr[i]; - } - } - mrb_raisef(mrb, E_INDEX_ERROR, "'%S' is not a struct member", mrb_sym2str(mrb, id)); - return mrb_nil_value(); /* not reached */ -} +static mrb_value struct_aref_sym(mrb_state *mrb, mrb_value obj, mrb_sym id); static mrb_value mrb_struct_ref(mrb_state *mrb, mrb_value obj) { - return mrb_struct_getmember(mrb, obj, mrb->c->ci->mid); + return struct_aref_sym(mrb, obj, mrb->c->ci->mid); } -static mrb_value mrb_struct_ref0(mrb_state* mrb, mrb_value obj) {return RSTRUCT_PTR(obj)[0];} -static mrb_value mrb_struct_ref1(mrb_state* mrb, mrb_value obj) {return RSTRUCT_PTR(obj)[1];} -static mrb_value mrb_struct_ref2(mrb_state* mrb, mrb_value obj) {return RSTRUCT_PTR(obj)[2];} -static mrb_value mrb_struct_ref3(mrb_state* mrb, mrb_value obj) {return RSTRUCT_PTR(obj)[3];} -static mrb_value mrb_struct_ref4(mrb_state* mrb, mrb_value obj) {return RSTRUCT_PTR(obj)[4];} -static mrb_value mrb_struct_ref5(mrb_state* mrb, mrb_value obj) {return RSTRUCT_PTR(obj)[5];} -static mrb_value mrb_struct_ref6(mrb_state* mrb, mrb_value obj) {return RSTRUCT_PTR(obj)[6];} -static mrb_value mrb_struct_ref7(mrb_state* mrb, mrb_value obj) {return RSTRUCT_PTR(obj)[7];} -static mrb_value mrb_struct_ref8(mrb_state* mrb, mrb_value obj) {return RSTRUCT_PTR(obj)[8];} -static mrb_value mrb_struct_ref9(mrb_state* mrb, mrb_value obj) {return RSTRUCT_PTR(obj)[9];} - -#define numberof(array) (int)(sizeof(array) / sizeof((array)[0])) -#define N_REF_FUNC numberof(ref_func) - -static const mrb_func_t ref_func[] = { - mrb_struct_ref0, - mrb_struct_ref1, - mrb_struct_ref2, - mrb_struct_ref3, - mrb_struct_ref4, - mrb_struct_ref5, - mrb_struct_ref6, - mrb_struct_ref7, - mrb_struct_ref8, - mrb_struct_ref9, -}; - static mrb_sym mrb_id_attrset(mrb_state *mrb, mrb_sym id) { @@ -171,40 +130,24 @@ mrb_id_attrset(mrb_state *mrb, mrb_sym id) return mid; } +static mrb_value mrb_struct_aset_sym(mrb_state *mrb, mrb_value s, mrb_sym id, mrb_value val); + static mrb_value -mrb_struct_set(mrb_state *mrb, mrb_value obj, mrb_value val) +mrb_struct_set_m(mrb_state *mrb, mrb_value obj) { + mrb_value val; + const char *name; - mrb_int i, len, slen; + mrb_int slen; mrb_sym mid; - mrb_value members, slot, *ptr; - const mrb_value *ptr_members; + + mrb_get_args(mrb, "o", &val); /* get base id */ name = mrb_sym2name_len(mrb, mrb->c->ci->mid, &slen); mid = mrb_intern(mrb, name, slen-1); /* omit last "=" */ - members = struct_members(mrb, obj); - ptr_members = RARRAY_PTR(members); - len = RARRAY_LEN(members); - ptr = RSTRUCT_PTR(obj); - for (i=0; i<len; i++) { - slot = ptr_members[i]; - if (mrb_symbol(slot) == mid) { - return ptr[i] = val; - } - } - mrb_raisef(mrb, E_INDEX_ERROR, "'%S' is not a struct member", mrb_sym2str(mrb, mid)); - return mrb_nil_value(); /* not reached */ -} - -static mrb_value -mrb_struct_set_m(mrb_state *mrb, mrb_value obj) -{ - mrb_value val; - - mrb_get_args(mrb, "o", &val); - return mrb_struct_set(mrb, obj, val); + return mrb_struct_aset_sym(mrb, obj, mid, val); } static mrb_bool @@ -234,12 +177,7 @@ make_struct_define_accessors(mrb_state *mrb, mrb_value members, struct RClass *c const char *name = mrb_sym2name_len(mrb, id, NULL); if (is_local_id(mrb, name) || is_const_id(mrb, name)) { - if (i < N_REF_FUNC) { - mrb_define_method_id(mrb, c, id, ref_func[i], MRB_ARGS_NONE()); - } - else { - mrb_define_method_id(mrb, c, id, mrb_struct_ref, MRB_ARGS_NONE()); - } + mrb_define_method_id(mrb, c, id, mrb_struct_ref, MRB_ARGS_NONE()); mrb_define_method_id(mrb, c, mrb_id_attrset(mrb, id), mrb_struct_set_m, MRB_ARGS_REQ(1)); mrb_gc_arena_restore(mrb, ai); } @@ -361,7 +299,7 @@ mrb_struct_s_def(mrb_state *mrb, mrb_value klass) } st = make_struct(mrb, name, rest, struct_class(mrb)); if (!mrb_nil_p(b)) { - mrb_yield_with_class(mrb, b, 1, &st, st, mrb_class_ptr(klass)); + mrb_yield_with_class(mrb, b, 1, &st, st, mrb_class_ptr(st)); } return st; @@ -433,22 +371,23 @@ mrb_struct_init_copy(mrb_state *mrb, mrb_value copy) } static mrb_value -struct_aref_sym(mrb_state *mrb, mrb_value s, mrb_sym id) +struct_aref_sym(mrb_state *mrb, mrb_value obj, mrb_sym id) { - mrb_value *ptr, members; + mrb_value members, *ptr; const mrb_value *ptr_members; mrb_int i, len; - ptr = RSTRUCT_PTR(s); - members = struct_members(mrb, s); + members = struct_members(mrb, obj); ptr_members = RARRAY_PTR(members); len = RARRAY_LEN(members); + ptr = RSTRUCT_PTR(obj); for (i=0; i<len; i++) { - if (mrb_symbol(ptr_members[i]) == id) { + mrb_value slot = ptr_members[i]; + if (mrb_symbol_p(slot) && mrb_symbol(slot) == id) { return ptr[i]; } } - mrb_name_error(mrb, id, "no member '%S' in struct", mrb_sym2str(mrb, id)); + mrb_raisef(mrb, E_INDEX_ERROR, "'%S' is not a struct member", mrb_sym2str(mrb, id)); return mrb_nil_value(); /* not reached */ } @@ -515,11 +454,6 @@ mrb_struct_aset_sym(mrb_state *mrb, mrb_value s, mrb_sym id, mrb_value val) members = struct_members(mrb, s); len = RARRAY_LEN(members); - if (RSTRUCT_LEN(s) != len) { - mrb_raisef(mrb, E_TYPE_ERROR, - "struct size differs (%S required %S given)", - mrb_fixnum_value(len), mrb_fixnum_value(RSTRUCT_LEN(s))); - } ptr = RSTRUCT_PTR(s); ptr_members = RARRAY_PTR(members); for (i=0; i<len; i++) { diff --git a/mrbgems/mruby-struct/test/struct.rb b/mrbgems/mruby-struct/test/struct.rb index 63a02817e..02ecf69e4 100644 --- a/mrbgems/mruby-struct/test/struct.rb +++ b/mrbgems/mruby-struct/test/struct.rb @@ -23,6 +23,9 @@ assert('Struct#==', '15.2.18.4.1') do cc1 = c.new(1,2) cc2 = c.new(1,2) assert_true cc1 == cc2 + + Struct.new(:m1, :m2) { def foo; end } + assert_raise(NoMethodError) { Struct.new(:m1).new.foo } end assert('Struct#[]', '15.2.18.4.2') do |
