diff options
| -rw-r--r-- | .travis.yml | 8 | ||||
| -rw-r--r-- | include/mruby/array.h | 127 | ||||
| -rw-r--r-- | include/mruby/hash.h | 88 | ||||
| -rw-r--r-- | include/mruby/istruct.h | 47 | ||||
| -rw-r--r-- | include/mruby/value.h | 3 | ||||
| -rw-r--r-- | mrbgems/mruby-inline-struct/mrbgem.rake | 5 | ||||
| -rw-r--r-- | mrbgems/mruby-inline-struct/test/inline.c | 83 | ||||
| -rw-r--r-- | mrbgems/mruby-inline-struct/test/inline.rb | 151 | ||||
| -rw-r--r-- | mrbgems/mruby-string-ext/mrblib/string.rb | 8 | ||||
| -rw-r--r-- | mrbgems/mruby-struct/src/struct.c | 2 | ||||
| -rw-r--r-- | src/class.c | 22 | ||||
| -rw-r--r-- | src/etc.c | 1 | ||||
| -rw-r--r-- | src/kernel.c | 4 | ||||
| -rw-r--r-- | src/object.c | 4 | ||||
| -rw-r--r-- | src/range.c | 9 | ||||
| -rw-r--r-- | src/string.c | 22 | ||||
| -rw-r--r-- | test/t/range.rb | 9 | ||||
| -rw-r--r-- | test/t/string.rb | 2 |
18 files changed, 546 insertions, 49 deletions
diff --git a/.travis.yml b/.travis.yml index 50feac2e0..8d201515c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,11 +16,3 @@ addons: env: MRUBY_CONFIG=travis_config.rb script: "./minirake all test" - -notifications: - # Update mruby-head installed on Travis CI so other projects can test against it. - webhooks: - urls: - - "https://rubies.travis-ci.org/rebuild/mruby-head" - on_success: always - on_failure: never diff --git a/include/mruby/array.h b/include/mruby/array.h index 8f9d5d502..e553faf92 100644 --- a/include/mruby/array.h +++ b/include/mruby/array.h @@ -54,14 +54,60 @@ MRB_API mrb_value mrb_ary_new_capa(mrb_state*, mrb_int); * Array.new * * @param mrb The mruby state reference. - * @return The initialized array + * @return The initialized array. */ MRB_API mrb_value mrb_ary_new(mrb_state *mrb); +/* + * Initializes a new array with initial values + * + * Equivalent to: + * + * Array[value1, value2, ...] + * + * @param mrb The mruby state reference. + * @param size The numer of values. + * @param vals The actual values. + * @return The initialized array. + */ MRB_API mrb_value mrb_ary_new_from_values(mrb_state *mrb, mrb_int size, const mrb_value *vals); + +/* + * Initializes a new array with two initial values + * + * Equivalent to: + * + * Array[car, cdr] + * + * @param mrb The mruby state reference. + * @param car The first value. + * @param cdr The second value. + * @return The initialized array. + */ MRB_API mrb_value mrb_assoc_new(mrb_state *mrb, mrb_value car, mrb_value cdr); -MRB_API void mrb_ary_concat(mrb_state*, mrb_value, mrb_value); -MRB_API mrb_value mrb_ary_splat(mrb_state*, mrb_value); + +/* + * Concatenate two arrays. The target array will be modified + * + * Equivalent to: + * ary.concat(other) + * + * @param mrb The mruby state reference. + * @param self The target array. + * @param other The array that will be concatenated to self. + */ +MRB_API void mrb_ary_concat(mrb_state *mrb, mrb_value self, mrb_value other); + +/* + * Create an array from the input. It tries calling to_a on the + * value. If value does not respond to that, it creates a new + * array with just this value. + * + * @param mrb The mruby state reference. + * @param value The value to change into an array. + * @return An array representation of value. + */ +MRB_API mrb_value mrb_ary_splat(mrb_state *mrb, mrb_value value); /* * Pushes value into array. @@ -84,8 +130,8 @@ MRB_API void mrb_ary_push(mrb_state *mrb, mrb_value array, mrb_value value); * ary.pop * * @param mrb The mruby state reference. - * @param ary The array from which the value will be poped. - * @return The poped value. + * @param ary The array from which the value will be popped. + * @return The popped value. */ MRB_API mrb_value mrb_ary_pop(mrb_state *mrb, mrb_value ary); @@ -117,14 +163,81 @@ MRB_API mrb_value mrb_ary_ref(mrb_state *mrb, mrb_value ary, mrb_int n); */ MRB_API void mrb_ary_set(mrb_state *mrb, mrb_value ary, mrb_int n, mrb_value val); -MRB_API void mrb_ary_replace(mrb_state *mrb, mrb_value a, mrb_value b); +/* + * Replace the array with another array + * + * Equivalent to: + * + * ary.replace(other) + * + * @param mrb The mruby state reference + * @param self The target array. + * @param other The array to replace it with. + */ +MRB_API void mrb_ary_replace(mrb_state *mrb, mrb_value self, mrb_value other); MRB_API mrb_value mrb_check_array_type(mrb_state *mrb, mrb_value self); + +/* + * Unshift an element into an array + * + * Equivalent to: + * + * ary.unshift(item) + * + * @param mrb The mruby state reference. + * @param self The target array. + * @param item The item to unshift. + */ MRB_API mrb_value mrb_ary_unshift(mrb_state *mrb, mrb_value self, mrb_value item); MRB_API mrb_value mrb_ary_entry(mrb_value ary, mrb_int offset); + +/* + * Shifts the first element from the array. + * + * Equivalent to: + * + * ary.shift + * + * @param mrb The mruby state reference. + * @param self The array from which the value will be shifted. + * @return The shifted value. + */ MRB_API mrb_value mrb_ary_shift(mrb_state *mrb, mrb_value self); + +/* + * Removes all elements from this array + * + * Equivalent to: + * + * ary.clear + * + * @param mrb The mruby state reference. + * @param self The target array. + * @return self + */ MRB_API mrb_value mrb_ary_clear(mrb_state *mrb, mrb_value self); + +/* + * Join the array elements together in a string + * + * Equivalent to: + * + * ary.join(sep="") + * + * @param mrb The mruby state reference. + * @param ary The target array + * @param sep The separater, can be NULL + */ MRB_API mrb_value mrb_ary_join(mrb_state *mrb, mrb_value ary, mrb_value sep); -MRB_API mrb_value mrb_ary_resize(mrb_state *mrb, mrb_value ary, mrb_int len); + +/* + * Update the capacity of the array + * + * @param mrb The mruby state reference. + * @param ary The target array. + * @param new_len The new capacity of the array + */ +MRB_API mrb_value mrb_ary_resize(mrb_state *mrb, mrb_value ary, mrb_int new_len); static inline mrb_int mrb_ary_len(mrb_state *mrb, mrb_value ary) diff --git a/include/mruby/hash.h b/include/mruby/hash.h index 922353322..55ad6a921 100644 --- a/include/mruby/hash.h +++ b/include/mruby/hash.h @@ -28,40 +28,126 @@ MRB_API mrb_value mrb_hash_new_capa(mrb_state*, int); /* * Initializes a new hash. + * + * Equivalent to: + * + * Hash.new + * + * @param mrb The mruby state reference. + * @return The initialized hash. */ MRB_API mrb_value mrb_hash_new(mrb_state *mrb); /* * Sets a keys and values to hashes. + * + * Equivalent to: + * + * hash[key] = val + * + * @param mrb The mruby state reference. + * @param hash The target hash. + * @param key The key to set. + * @param val The value to set. + * @return The value. */ MRB_API void mrb_hash_set(mrb_state *mrb, mrb_value hash, mrb_value key, mrb_value val); /* - * Gets a value from a key. + * Gets a value from a key. If the key is not found, the default of the + * hash is used. + * + * Equivalent to: + * + * hash[key] + * + * @param mrb The mruby state reference. + * @param hash The target hash. + * @param key The key to get. + * @return The found value. */ MRB_API mrb_value mrb_hash_get(mrb_state *mrb, mrb_value hash, mrb_value key); +/* + * Gets a value from a key. If the key is not found, the default parameter is + * used. + * + * Equivalent to: + * + * hash.hash_key?(key) ? hash[key] : def + * + * @param mrb The mruby state reference. + * @param hash The target hash. + * @param key The key to get. + * @param def The default value. + * @return The found value. + */ MRB_API mrb_value mrb_hash_fetch(mrb_state *mrb, mrb_value hash, mrb_value key, mrb_value def); /* * Deletes hash key and value pair. + * + * Equivalent to: + * + * hash.delete(key) + * + * @param mrb The mruby state reference. + * @param hash The target hash. + * @param key The key to delete. + * @return The deleted value. */ MRB_API mrb_value mrb_hash_delete_key(mrb_state *mrb, mrb_value hash, mrb_value key); /* * Gets an array of keys. + * + * Equivalent to: + * + * hash.keys + * + * @param mrb The mruby state reference. + * @param hash The target hash. + * @return An array with the keys of the hash. */ MRB_API mrb_value mrb_hash_keys(mrb_state *mrb, mrb_value hash); MRB_API mrb_value mrb_check_hash_type(mrb_state *mrb, mrb_value hash); + +/* + * Check if the hash is empty + * + * Equivalent to: + * + * hash.empty? + * + * @param mrb The mruby state reference. + * @param self The target hash. + * @return True if the hash is empty, false otherwise. + */ MRB_API mrb_value mrb_hash_empty_p(mrb_state *mrb, mrb_value self); /* * Gets an array of values. + * + * Equivalent to: + * + * hash.values + * + * @param mrb The mruby state reference. + * @param hash The target hash. + * @return An array with the values of the hash. */ MRB_API mrb_value mrb_hash_values(mrb_state *mrb, mrb_value hash); /* * Clears the hash. + * + * Equivalent to: + * + * hash.clear + * + * @param mrb The mruby state reference. + * @param hash The target hash. + * @return The hash */ MRB_API mrb_value mrb_hash_clear(mrb_state *mrb, mrb_value hash); diff --git a/include/mruby/istruct.h b/include/mruby/istruct.h new file mode 100644 index 000000000..293a13788 --- /dev/null +++ b/include/mruby/istruct.h @@ -0,0 +1,47 @@ +/* +** mruby/instruct.h - Inline structures +** +** See Copyright Notice in mruby.h +*/ + +#ifndef MRUBY_ISTRUCT_H +#define MRUBY_ISTRUCT_H + +#include "common.h" +#include <string.h> + +/** + * Inline structures that fit in RVALUE + * + * They cannot have finalizer, and cannot have instance variables. + */ +MRB_BEGIN_DECL + +#define ISTRUCT_DATA_SIZE (sizeof(void*) * 3) + +struct RIstruct { + MRB_OBJECT_HEADER; + char inline_data[ISTRUCT_DATA_SIZE]; +}; + +#define RISTRUCT(obj) ((struct RIstruct*)(mrb_ptr(obj))) +#define ISTRUCT_PTR(obj) (RISTRUCT(obj)->inline_data) + +MRB_INLINE mrb_int mrb_istruct_size() +{ + return ISTRUCT_DATA_SIZE; +} + +MRB_INLINE void* mrb_istruct_ptr(mrb_value object) +{ + return ISTRUCT_PTR(object); +} + +MRB_INLINE void mrb_istruct_copy(mrb_value dest, mrb_value src) +{ + memcpy(ISTRUCT_PTR(dest), ISTRUCT_PTR(src), ISTRUCT_DATA_SIZE); +} + +MRB_END_DECL + +#endif /* MRUBY_ISTRUCT_H */ diff --git a/include/mruby/value.h b/include/mruby/value.h index 4330b9441..6b29ab273 100644 --- a/include/mruby/value.h +++ b/include/mruby/value.h @@ -116,7 +116,8 @@ enum mrb_vtype { MRB_TT_ENV, /* 20 */ MRB_TT_DATA, /* 21 */ MRB_TT_FIBER, /* 22 */ - MRB_TT_MAXDEFINE /* 23 */ + MRB_TT_ISTRUCT, /* 23 */ + MRB_TT_MAXDEFINE /* 24 */ }; #include <mruby/object.h> diff --git a/mrbgems/mruby-inline-struct/mrbgem.rake b/mrbgems/mruby-inline-struct/mrbgem.rake new file mode 100644 index 000000000..91ad9f44b --- /dev/null +++ b/mrbgems/mruby-inline-struct/mrbgem.rake @@ -0,0 +1,5 @@ +MRuby::Gem::Specification.new('mruby-inline-struct') do |spec| + spec.license = 'MIT' + spec.author = 'mruby developers' + spec.summary = 'inline structure' +end diff --git a/mrbgems/mruby-inline-struct/test/inline.c b/mrbgems/mruby-inline-struct/test/inline.c new file mode 100644 index 000000000..49ef31d00 --- /dev/null +++ b/mrbgems/mruby-inline-struct/test/inline.c @@ -0,0 +1,83 @@ +#include <mruby.h> +#include <mruby/class.h> +#include <mruby/string.h> +#include <mruby/istruct.h> + +static mrb_value +istruct_test_initialize(mrb_state *mrb, mrb_value self) +{ + char *string = mrb_istruct_ptr(self); + mrb_int size = mrb_istruct_size(); + mrb_value object; + mrb_get_args(mrb, "o", &object); + + if (mrb_float_p(object)) + { + snprintf(string, size, "float(%.3f)", mrb_float(object)); + } + else if (mrb_fixnum_p(object)) + { + snprintf(string, size, "fixnum(%d)", mrb_fixnum(object)); + } + else if (mrb_string_p(object)) + { + snprintf(string, size, "string(%s)", mrb_string_value_cstr(mrb, &object)); + } + + string[size - 1] = 0; // force NULL at the end + return self; +} + +static mrb_value +istruct_test_to_s(mrb_state *mrb, mrb_value self) +{ + return mrb_str_new_cstr(mrb, mrb_istruct_ptr(self)); +} + +static mrb_value +istruct_test_length(mrb_state *mrb, mrb_value self) +{ + return mrb_fixnum_value(mrb_istruct_size()); +} + +static mrb_value +istruct_test_test_receive(mrb_state *mrb, mrb_value self) +{ + mrb_value object; + mrb_get_args(mrb, "o", &object); + if (mrb_obj_class(mrb, object) != mrb_class_get(mrb, "InlineStructTest")) + { + mrb_raisef(mrb, E_TYPE_ERROR, "Expected InlineStructTest"); + } + return mrb_bool_value(((char*)mrb_istruct_ptr(object))[0] == 's'); +} + +static mrb_value +istruct_test_test_receive_direct(mrb_state *mrb, mrb_value self) +{ + char *ptr; + mrb_get_args(mrb, "I", &ptr); + return mrb_bool_value(ptr[0] == 's'); +} + +static mrb_value +istruct_test_mutate(mrb_state *mrb, mrb_value self) +{ + char *ptr = mrb_istruct_ptr(self); + memcpy(ptr, "mutate", 6); + return mrb_nil_value(); +} + +void mrb_mruby_inline_struct_gem_test(mrb_state *mrb) +{ + struct RClass *cls; + + cls = mrb_define_class(mrb, "InlineStructTest", mrb->object_class); + MRB_SET_INSTANCE_TT(cls, MRB_TT_ISTRUCT); + mrb_define_method(mrb, cls, "initialize", istruct_test_initialize, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, cls, "to_s", istruct_test_to_s, MRB_ARGS_NONE()); + mrb_define_method(mrb, cls, "mutate", istruct_test_mutate, MRB_ARGS_NONE()); + mrb_define_class_method(mrb, cls, "length", istruct_test_length, MRB_ARGS_NONE()); + mrb_define_class_method(mrb, cls, "test_receive", istruct_test_test_receive, MRB_ARGS_REQ(1)); + mrb_define_class_method(mrb, cls, "test_receive_direct", istruct_test_test_receive_direct, MRB_ARGS_REQ(1)); +} diff --git a/mrbgems/mruby-inline-struct/test/inline.rb b/mrbgems/mruby-inline-struct/test/inline.rb new file mode 100644 index 000000000..495859232 --- /dev/null +++ b/mrbgems/mruby-inline-struct/test/inline.rb @@ -0,0 +1,151 @@ +## +# InlineStruct Test + +class InlineStructTest + def extra_method + :ok + end + + def test_ivar_set + @var = :ivar + end + + def test_ivar_get + @vat + end +end + +assert('InlineStructTest#dup') do + obj = InlineStructTest.new(1) + assert_equal obj.to_s, 'fixnum(1)' + assert_equal obj.dup.to_s, 'fixnum(1)' +end + +assert('InlineStructTest#clone') do + obj = InlineStructTest.new(1) + assert_equal obj.to_s, 'fixnum(1)' + assert_equal obj.clone.to_s, 'fixnum(1)' +end + +assert('InlineStruct#object_id') do + obj1 = InlineStructTest.new(1) + obj2 = InlineStructTest.new(1) + assert_not_equal obj1, obj2 + assert_not_equal obj1.object_id, obj2.object_id + assert_not_equal obj1.object_id, obj1.dup.object_id + assert_not_equal obj1.object_id, obj1.clone.object_id +end + +assert('InlineStructTest#mutate (dup)') do + obj1 = InlineStructTest.new("foo") + assert_equal obj1.to_s, "string(foo)" + obj2 = obj1.dup + assert_equal obj2.to_s, "string(foo)" + obj1.mutate + assert_equal obj1.to_s, "mutate(foo)" + assert_equal obj2.to_s, "string(foo)" +end + +assert('InlineStructTest#mutate (clone)') do + obj1 = InlineStructTest.new("foo") + assert_equal obj1.to_s, "string(foo)" + obj2 = obj1.clone + assert_equal obj2.to_s, "string(foo)" + obj1.mutate + assert_equal obj1.to_s, "mutate(foo)" + assert_equal obj2.to_s, "string(foo)" +end + +assert('InlineStructTest#test_receive(string)') do + assert_equal InlineStructTest.test_receive(InlineStructTest.new('a')), true +end + +assert('InlineStructTest#test_receive(float)') do + assert_equal InlineStructTest.test_receive(InlineStructTest.new(1.25)), false +end + +assert('InlineStructTest#test_receive(invalid object)') do + assert_raise(TypeError) do + InlineStructTest.test_receive([]) + end +end + +assert('InlineStructTest#test_receive(string)') do + assert_equal InlineStructTest.test_receive_direct(InlineStructTest.new('a')), true +end + +assert('InlineStructTest#test_receive(float)') do + assert_equal InlineStructTest.test_receive_direct(InlineStructTest.new(1.25)), false +end + +assert('InlineStructTest#test_receive(invalid object)') do + assert_raise(TypeError) do + InlineStructTest.test_receive_direct([]) + end +end + +assert('InlineStructTest#extra_method') do + assert_equal InlineStructTest.new(1).extra_method, :ok +end + +assert('InlineStructTest instance variable') do + obj = InlineStructTest.new(1) + assert_raise(ArgumentError) do + obj.test_ivar_set + end + assert_equal obj.test_ivar_get, nil +end + +# 64-bit mode +if InlineStructTest.length == 24 + assert('InlineStructTest length [64 bit]') do + assert_equal InlineStructTest.length, 3 * 8 + end + + assert('InlineStructTest w/float [64 bit]') do + obj = InlineStructTest.new(1.25) + assert_equal obj.to_s, "float(1.250)" + end + + assert('InlineStructTest w/fixnum [64 bit]') do + obj = InlineStructTest.new(42) + assert_equal obj.to_s, "fixnum(42)" + end + + assert('InlineStructTest w/string [64 bit]') do + obj = InlineStructTest.new("hello") + assert_equal obj.to_s, "string(hello)" + end + + assert('InlineStructTest w/long string [64 bit]') do + obj = InlineStructTest.new("this won't fit in 3 * 8 bytes available for the structure") + assert_equal obj.to_s, "string(this won't fit i" + end +end + +# 32-bit mode +if InlineStructTest.length == 12 + assert('InlineStructTest length [32 bit]') do + assert_equal InlineStructTest.length, 3 * 4 + end + + assert('InlineStructTest w/float [32 bit]') do + obj = InlineStructTest.new(1.25) + assert_equal obj.to_s, "float(1.250" + end + + assert('InlineStructTest w/fixnum [32 bit]') do + obj = InlineStructTest.new(42) + assert_equal obj.to_s, "fixnum(42)" + end + + assert('InlineStructTest w/string [32 bit]') do + obj = InlineStructTest.new("hello") + assert_equal obj.to_s, "string(hell" + end + + assert('InlineStructTest w/long string [32 bit]') do + obj = InlineStructTest.new("this won't fit in 3 * 4 bytes available for the structure") + assert_equal obj.to_s, "string(this" + end +end diff --git a/mrbgems/mruby-string-ext/mrblib/string.rb b/mrbgems/mruby-string-ext/mrblib/string.rb index c3b765a5f..e6fbe7ddc 100644 --- a/mrbgems/mruby-string-ext/mrblib/string.rb +++ b/mrbgems/mruby-string-ext/mrblib/string.rb @@ -45,7 +45,7 @@ class String def lstrip a = 0 z = self.size - 1 - a += 1 while " \f\n\r\t\v".include?(self[a]) and a <= z + a += 1 while a <= z and " \f\n\r\t\v".include?(self[a]) (z >= 0) ? self[a..z] : "" end @@ -62,7 +62,7 @@ class String def rstrip a = 0 z = self.size - 1 - z -= 1 while " \f\n\r\t\v\0".include?(self[z]) and a <= z + z -= 1 while a <= z and " \f\n\r\t\v\0".include?(self[z]) (z >= 0) ? self[a..z] : "" end @@ -78,8 +78,8 @@ class String def strip a = 0 z = self.size - 1 - a += 1 while " \f\n\r\t\v".include?(self[a]) and a <= z - z -= 1 while " \f\n\r\t\v\0".include?(self[z]) and a <= z + a += 1 while a <= z and " \f\n\r\t\v".include?(self[a]) + z -= 1 while a <= z and " \f\n\r\t\v\0".include?(self[z]) (z >= 0) ? self[a..z] : "" end diff --git a/mrbgems/mruby-struct/src/struct.c b/mrbgems/mruby-struct/src/struct.c index 1a06e0c12..0ccb7f4cb 100644 --- a/mrbgems/mruby-struct/src/struct.c +++ b/mrbgems/mruby-struct/src/struct.c @@ -703,7 +703,7 @@ mrb_mruby_struct_gem_init(mrb_state* mrb) mrb_define_method(mrb, st, "to_a", mrb_struct_to_a, MRB_ARGS_NONE()); mrb_define_method(mrb, st, "values", mrb_struct_to_a, MRB_ARGS_NONE()); mrb_define_method(mrb, st, "to_h", mrb_struct_to_h, MRB_ARGS_NONE()); - mrb_define_method(mrb, st, "values_at", mrb_struct_values_at, MRB_ARGS_NONE()); + mrb_define_method(mrb, st, "values_at", mrb_struct_values_at, MRB_ARGS_ANY()); } void diff --git a/src/class.c b/src/class.c index e5d60a693..d02253c57 100644 --- a/src/class.c +++ b/src/class.c @@ -14,6 +14,7 @@ #include <mruby/variable.h> #include <mruby/error.h> #include <mruby/data.h> +#include <mruby/istruct.h> KHASH_DEFINE(mt, mrb_sym, struct RProc*, TRUE, kh_int_hash_func, kh_int_hash_equal) @@ -491,6 +492,7 @@ to_sym(mrb_state *mrb, mrb_value ss) b: Boolean [mrb_bool] n: Symbol [mrb_sym] d: Data [void*,mrb_data_type const] 2nd argument will be used to check data type so it won't be modified + I: Inline struct [void*] &: Block [mrb_value] *: rest argument [mrb_value*,mrb_int] Receive the rest of the arguments as an array. |: optional Next argument of '|' and later are optional. @@ -702,6 +704,24 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) } } break; + case 'I': + { + void* *p; + mrb_value ss; + + p = va_arg(ap, void**); + if (i < argc) { + ss = ARGV[arg_i]; + if (mrb_type(ss) != MRB_TT_ISTRUCT) + { + mrb_raisef(mrb, E_TYPE_ERROR, "%S is not inline struct", ss); + } + *p = mrb_istruct_ptr(ss); + arg_i++; + i++; + } + } + break; case 'f': { mrb_float *p; @@ -2287,7 +2307,7 @@ mrb_init_class(mrb_state *mrb) mrb_define_method(mrb, mod, "constants", mrb_mod_constants, MRB_ARGS_OPT(1)); /* 15.2.2.4.24 */ mrb_define_method(mrb, mod, "remove_const", mrb_mod_remove_const, MRB_ARGS_REQ(1)); /* 15.2.2.4.40 */ mrb_define_method(mrb, mod, "const_missing", mrb_mod_const_missing, MRB_ARGS_REQ(1)); - mrb_define_method(mrb, mod, "define_method", mod_define_method, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, mod, "define_method", mod_define_method, MRB_ARGS_ARG(1,1)); mrb_define_method(mrb, mod, "class_variables", mrb_mod_class_variables, MRB_ARGS_NONE()); /* 15.2.2.4.19 */ mrb_define_method(mrb, mod, "===", mrb_mod_eqq, MRB_ARGS_REQ(1)); mrb_define_class_method(mrb, mod, "constants", mrb_mod_s_constants, MRB_ARGS_ANY()); /* 15.2.2.3.1 */ @@ -139,6 +139,7 @@ mrb_obj_id(mrb_value obj) case MRB_TT_EXCEPTION: case MRB_TT_FILE: case MRB_TT_DATA: + case MRB_TT_ISTRUCT: default: return MakeID(mrb_ptr(obj)); } diff --git a/src/kernel.c b/src/kernel.c index df237cd46..8b1ef80a0 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -11,6 +11,7 @@ #include <mruby/string.h> #include <mruby/variable.h> #include <mruby/error.h> +#include <mruby/istruct.h> typedef enum { NOEX_PUBLIC = 0x00, @@ -301,6 +302,9 @@ init_copy(mrb_state *mrb, mrb_value dest, mrb_value obj) case MRB_TT_EXCEPTION: mrb_iv_copy(mrb, dest, obj); break; + case MRB_TT_ISTRUCT: + mrb_istruct_copy(dest, obj); + break; default: break; diff --git a/src/object.c b/src/object.c index bb1a4ebc4..392432b0f 100644 --- a/src/object.c +++ b/src/object.c @@ -348,7 +348,7 @@ mrb_check_convert_type(mrb_state *mrb, mrb_value val, enum mrb_vtype type, const { mrb_value v; - if (mrb_type(val) == type && type != MRB_TT_DATA) return val; + if (mrb_type(val) == type && type != MRB_TT_DATA && type != MRB_TT_ISTRUCT) return val; v = convert_type(mrb, val, tname, method, FALSE); if (mrb_nil_p(v) || mrb_type(v) != type) return mrb_nil_value(); return v; @@ -390,7 +390,7 @@ mrb_check_type(mrb_state *mrb, mrb_value x, enum mrb_vtype t) enum mrb_vtype xt; xt = mrb_type(x); - if ((xt != t) || (xt == MRB_TT_DATA)) { + if ((xt != t) || (xt == MRB_TT_DATA) || (xt == MRB_TT_ISTRUCT)) { while (type->type < MRB_TT_MAXDEFINE) { if (type->type == t) { const char *etype; diff --git a/src/range.c b/src/range.c index 079a1035e..f0a976e53 100644 --- a/src/range.c +++ b/src/range.c @@ -129,6 +129,9 @@ mrb_range_initialize(mrb_state *mrb, mrb_value range) exclusive = FALSE; } /* Ranges are immutable, so that they should be initialized only once. */ + if (mrb_range_ptr(range)->edges) { + mrb_name_error(mrb, mrb_intern_lit(mrb, "initialize"), "`initialize' called twice"); + } range_init(mrb, range, beg, end, exclusive); return range; } @@ -227,9 +230,9 @@ mrb_range_include(mrb_state *mrb, mrb_value range) beg = r->edges->beg; end = r->edges->end; - include_p = r_le(mrb, beg, val) && /* beg <= val */ - ((r->excl && r_gt(mrb, end, val)) || /* end > val */ - (r_ge(mrb, end, val))); /* end >= val */ + include_p = r_le(mrb, beg, val) && /* beg <= val */ + (r->excl ? r_gt(mrb, end, val) /* end > val */ + : r_ge(mrb, end, val)); /* end >= val */ return mrb_bool_value(include_p); } diff --git a/src/string.c b/src/string.c index 15fcc502a..f8ab9478f 100644 --- a/src/string.c +++ b/src/string.c @@ -1530,22 +1530,12 @@ mrb_str_hash_m(mrb_state *mrb, mrb_value self) static mrb_value mrb_str_include(mrb_state *mrb, mrb_value self) { - mrb_int i; mrb_value str2; - mrb_bool include_p; - - mrb_get_args(mrb, "o", &str2); - if (mrb_fixnum_p(str2)) { - include_p = (memchr(RSTRING_PTR(self), mrb_fixnum(str2), RSTRING_LEN(self)) != NULL); - } - else { - str2 = mrb_str_to_str(mrb, str2); - i = str_index(mrb, self, str2, 0); - - include_p = (i != -1); - } - return mrb_bool_value(include_p); + mrb_get_args(mrb, "S", &str2); + if (str_index(mrb, self, str2, 0) < 0) + return mrb_bool_value(FALSE); + return mrb_bool_value(TRUE); } /* 15.2.10.5.22 */ @@ -2723,8 +2713,8 @@ mrb_init_string(mrb_state *mrb) mrb_define_method(mrb, s, "capitalize!", mrb_str_capitalize_bang, MRB_ARGS_NONE()); /* 15.2.10.5.8 */ mrb_define_method(mrb, s, "chomp", mrb_str_chomp, MRB_ARGS_ANY()); /* 15.2.10.5.9 */ mrb_define_method(mrb, s, "chomp!", mrb_str_chomp_bang, MRB_ARGS_ANY()); /* 15.2.10.5.10 */ - mrb_define_method(mrb, s, "chop", mrb_str_chop, MRB_ARGS_REQ(1)); /* 15.2.10.5.11 */ - mrb_define_method(mrb, s, "chop!", mrb_str_chop_bang, MRB_ARGS_REQ(1)); /* 15.2.10.5.12 */ + mrb_define_method(mrb, s, "chop", mrb_str_chop, MRB_ARGS_NONE()); /* 15.2.10.5.11 */ + mrb_define_method(mrb, s, "chop!", mrb_str_chop_bang, MRB_ARGS_NONE()); /* 15.2.10.5.12 */ mrb_define_method(mrb, s, "downcase", mrb_str_downcase, MRB_ARGS_NONE()); /* 15.2.10.5.13 */ mrb_define_method(mrb, s, "downcase!", mrb_str_downcase_bang, MRB_ARGS_NONE()); /* 15.2.10.5.14 */ mrb_define_method(mrb, s, "empty?", mrb_str_empty_p, MRB_ARGS_NONE()); /* 15.2.10.5.16 */ diff --git a/test/t/range.rb b/test/t/range.rb index 278b26902..5391369de 100644 --- a/test/t/range.rb +++ b/test/t/range.rb @@ -43,10 +43,11 @@ assert('Range#first', '15.2.14.4.7') do end assert('Range#include?', '15.2.14.4.8') do - a = (1..10) + assert_true (1..10).include?(10) + assert_false (1..10).include?(11) - assert_true a.include?(5) - assert_false a.include?(20) + assert_true (1...10).include?(9) + assert_false (1...10).include?(10) end assert('Range#initialize', '15.2.14.4.9') do @@ -57,6 +58,8 @@ assert('Range#initialize', '15.2.14.4.9') do assert_true a.exclude_end? assert_equal (1..10), b assert_false b.exclude_end? + + assert_raise(NameError) { (0..1).send(:initialize, 1, 3) } end assert('Range#last', '15.2.14.4.10') do diff --git a/test/t/string.rb b/test/t/string.rb index fbaada451..e67389b5c 100644 --- a/test/t/string.rb +++ b/test/t/string.rb @@ -381,8 +381,6 @@ assert('String#hash', '15.2.10.5.20') do end assert('String#include?', '15.2.10.5.21') do - assert_true 'abc'.include?(97) - assert_false 'abc'.include?(100) assert_true 'abc'.include?('a') assert_false 'abc'.include?('d') end |
