diff options
| author | Yukihiro "Matz" Matsumoto <[email protected]> | 2016-12-12 00:49:23 +0900 |
|---|---|---|
| committer | GitHub <[email protected]> | 2016-12-12 00:49:23 +0900 |
| commit | 1fbad32f8bce2a10c591d0e44796bc34913a0e8c (patch) | |
| tree | 8ba3d7bd9992f0097f99a034012565adb43c4d4a | |
| parent | 3cc913490b708fe4d0e78e48f86e6e39cf3d8576 (diff) | |
| parent | 10bb7ad693e7c7443de924a39c1fedb4461108ba (diff) | |
| download | mruby-1fbad32f8bce2a10c591d0e44796bc34913a0e8c.tar.gz mruby-1fbad32f8bce2a10c591d0e44796bc34913a0e8c.zip | |
Merge pull request #3340 from k0kubun/object-freeze
Implement Object#freeze
| -rw-r--r-- | include/mruby/class.h | 1 | ||||
| -rw-r--r-- | include/mruby/object.h | 4 | ||||
| -rw-r--r-- | include/mruby/string.h | 5 | ||||
| -rw-r--r-- | src/array.c | 4 | ||||
| -rw-r--r-- | src/hash.c | 7 | ||||
| -rw-r--r-- | src/kernel.c | 10 | ||||
| -rw-r--r-- | src/string.c | 15 | ||||
| -rw-r--r-- | test/t/array.rb | 7 | ||||
| -rw-r--r-- | test/t/hash.rb | 7 | ||||
| -rw-r--r-- | test/t/kernel.rb | 5 |
10 files changed, 45 insertions, 20 deletions
diff --git a/include/mruby/class.h b/include/mruby/class.h index 246e82e59..ce953af3b 100644 --- a/include/mruby/class.h +++ b/include/mruby/class.h @@ -52,6 +52,7 @@ mrb_class(mrb_state *mrb, mrb_value v) } // TODO: figure out where to put user flags +#define MRB_FLAG_IS_FROZEN (1 << 18) #define MRB_FLAG_IS_PREPENDED (1 << 19) #define MRB_FLAG_IS_ORIGIN (1 << 20) #define MRB_CLASS_ORIGIN(c) do {\ diff --git a/include/mruby/object.h b/include/mruby/object.h index 9fbfe34f3..da44027e1 100644 --- a/include/mruby/object.h +++ b/include/mruby/object.h @@ -22,6 +22,10 @@ struct RBasic { }; #define mrb_basic_ptr(v) ((struct RBasic*)(mrb_ptr(v))) +#define RBASIC_FROZEN_P(o) ((o)->flags & MRB_FLAG_IS_FROZEN) +#define RBASIC_SET_FROZEN_FLAG(o) ((o)->flags |= MRB_FLAG_IS_FROZEN) +#define RBASIC_UNSET_FROZEN_FLAG(o) ((o)->flags &= ~MRB_FLAG_IS_FROZEN) + struct RObject { MRB_OBJECT_HEADER; struct iv_tbl *iv; diff --git a/include/mruby/string.h b/include/mruby/string.h index b30c1ed98..9ccf8f187 100644 --- a/include/mruby/string.h +++ b/include/mruby/string.h @@ -62,10 +62,6 @@ struct RString { #define RSTR_SET_NOFREE_FLAG(s) ((s)->flags |= MRB_STR_NOFREE) #define RSTR_UNSET_NOFREE_FLAG(s) ((s)->flags &= ~MRB_STR_NOFREE) -#define RSTR_FROZEN_P(s) ((s)->flags & MRB_STR_FROZEN) -#define RSTR_SET_FROZEN_FLAG(s) ((s)->flags |= MRB_STR_FROZEN) -#define RSTR_UNSET_FROZEN_FLAG(s) ((s)->flags &= ~MRB_STR_FROZEN) - /* * Returns a pointer from a Ruby string */ @@ -80,7 +76,6 @@ MRB_API mrb_int mrb_str_strlen(mrb_state*, struct RString*); #define MRB_STR_SHARED 1 #define MRB_STR_NOFREE 2 -#define MRB_STR_FROZEN 4 #define MRB_STR_NO_UTF 8 #define MRB_STR_EMBED 16 #define MRB_STR_EMBED_LEN_MASK 0x3e0 diff --git a/src/array.c b/src/array.c index f6599bd5b..c6bac7b47 100644 --- a/src/array.c +++ b/src/array.c @@ -108,6 +108,10 @@ ary_fill_with_nil(mrb_value *ptr, mrb_int size) static void ary_modify(mrb_state *mrb, struct RArray *a) { + if (RBASIC_FROZEN_P(a)) { + mrb_raise(mrb, E_RUNTIME_ERROR, "can't modify frozen array"); + } + if (ARY_SHARED_P(a)) { mrb_shared_array *shared = a->aux.shared; diff --git a/src/hash.c b/src/hash.c index 93fe656e0..d0e865b5c 100644 --- a/src/hash.c +++ b/src/hash.c @@ -98,9 +98,9 @@ static void mrb_hash_modify(mrb_state *mrb, mrb_value hash); static inline mrb_value mrb_hash_ht_key(mrb_state *mrb, mrb_value key) { - if (mrb_string_p(key) && !RSTR_FROZEN_P(mrb_str_ptr(key))) { + if (mrb_string_p(key) && !RBASIC_FROZEN_P(mrb_str_ptr(key))) { key = mrb_str_dup(mrb, key); - RSTR_SET_FROZEN_FLAG(mrb_str_ptr(key)); + RBASIC_SET_FROZEN_FLAG(mrb_str_ptr(key)); } return key; } @@ -278,6 +278,9 @@ mrb_hash_tbl(mrb_state *mrb, mrb_value hash) static void mrb_hash_modify(mrb_state *mrb, mrb_value hash) { + if (RBASIC_FROZEN_P(mrb_hash_ptr(hash))) { + mrb_raise(mrb, E_RUNTIME_ERROR, "can't modify frozen hash"); + } mrb_hash_tbl(mrb, hash); } diff --git a/src/kernel.c b/src/kernel.c index c63e05596..78e57a17a 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -450,6 +450,15 @@ mrb_obj_extend_m(mrb_state *mrb, mrb_value self) return mrb_obj_extend(mrb, argc, argv, self); } +static mrb_value +mrb_obj_freeze(mrb_state *mrb, mrb_value self) +{ + struct RBasic *b = mrb_basic_ptr(self); + + RBASIC_SET_FROZEN_FLAG(b); + return self; +} + /* 15.3.1.3.15 */ /* * call-seq: @@ -1124,6 +1133,7 @@ mrb_init_kernel(mrb_state *mrb) mrb_define_method(mrb, krn, "eql?", mrb_obj_equal_m, MRB_ARGS_REQ(1)); /* 15.3.1.3.10 */ mrb_define_method(mrb, krn, "equal?", mrb_obj_equal_m, MRB_ARGS_REQ(1)); /* 15.3.1.3.11 */ mrb_define_method(mrb, krn, "extend", mrb_obj_extend_m, MRB_ARGS_ANY()); /* 15.3.1.3.13 */ + mrb_define_method(mrb, krn, "freeze", mrb_obj_freeze, MRB_ARGS_NONE()); mrb_define_method(mrb, krn, "global_variables", mrb_f_global_variables, MRB_ARGS_NONE()); /* 15.3.1.3.14 */ mrb_define_method(mrb, krn, "hash", mrb_obj_hash, MRB_ARGS_NONE()); /* 15.3.1.3.15 */ mrb_define_method(mrb, krn, "initialize_copy", mrb_obj_init_copy, MRB_ARGS_REQ(1)); /* 15.3.1.3.16 */ diff --git a/src/string.c b/src/string.c index a4f8085ec..7234ecf2b 100644 --- a/src/string.c +++ b/src/string.c @@ -501,7 +501,7 @@ str_index(mrb_state *mrb, mrb_value str, mrb_value sub, mrb_int offset) static void check_frozen(mrb_state *mrb, struct RString *s) { - if (RSTR_FROZEN_P(s)) { + if (RBASIC_FROZEN_P(s)) { mrb_raise(mrb, E_RUNTIME_ERROR, "can't modify frozen string"); } } @@ -700,15 +700,6 @@ mrb_str_modify(mrb_state *mrb, struct RString *s) } } -static mrb_value -mrb_str_freeze(mrb_state *mrb, mrb_value str) -{ - struct RString *s = mrb_str_ptr(str); - - RSTR_SET_FROZEN_FLAG(s); - return str; -} - MRB_API mrb_value mrb_str_resize(mrb_state *mrb, mrb_value str, mrb_int len) { @@ -2217,7 +2208,7 @@ mrb_string_value_cstr(mrb_state *mrb, mrb_value *ptr) char *p = RSTR_PTR(ps); if (!p || p[len] != '\0') { - if (RSTR_FROZEN_P(ps)) { + if (RBASIC_FROZEN_P(ps)) { *ptr = str = mrb_str_dup(mrb, str); ps = mrb_str_ptr(str); } @@ -2746,8 +2737,6 @@ mrb_init_string(mrb_state *mrb) mrb_define_method(mrb, s, "upcase!", mrb_str_upcase_bang, MRB_ARGS_NONE()); /* 15.2.10.5.43 */ mrb_define_method(mrb, s, "inspect", mrb_str_inspect, MRB_ARGS_NONE()); /* 15.2.10.5.46(x) */ mrb_define_method(mrb, s, "bytes", mrb_str_bytes, MRB_ARGS_NONE()); - - mrb_define_method(mrb, s, "freeze", mrb_str_freeze, MRB_ARGS_NONE()); } /* diff --git a/test/t/array.rb b/test/t/array.rb index 9cc2f64ad..cf7ed4704 100644 --- a/test/t/array.rb +++ b/test/t/array.rb @@ -373,3 +373,10 @@ assert("Array#rindex") do $a = [2, 3, 4, 5, 6, 7, 8, 9, 10, Sneaky.new] assert_equal 0, $a.rindex(1) end + +assert('Array#freeze') do + a = [].freeze + assert_raise(RuntimeError) do + a[0] = 1 + end +end diff --git a/test/t/hash.rb b/test/t/hash.rb index f076db8e5..c63b8c009 100644 --- a/test/t/hash.rb +++ b/test/t/hash.rb @@ -366,3 +366,10 @@ assert('Hash#rehash') do h.rehash assert_equal("b", h[[:b]]) end + +assert('Hash#freeze') do + h = {}.freeze + assert_raise(RuntimeError) do + h[:a] = 'b' + end +end diff --git a/test/t/kernel.rb b/test/t/kernel.rb index e59bd6a10..42abed9df 100644 --- a/test/t/kernel.rb +++ b/test/t/kernel.rb @@ -257,6 +257,11 @@ assert('Kernel#extend works on toplevel', '15.3.1.3.13') do assert_true respond_to?(:test_method) end +assert('Kernel#freeze') do + obj = Object.new + assert_equal obj, obj.freeze +end + assert('Kernel#global_variables', '15.3.1.3.14') do assert_equal Array, global_variables.class end |
