Commit 10bb7ad6 authored by Takashi Kokubun's avatar Takashi Kokubun

Implement Object#freeze

parent 3cc91349
...@@ -52,6 +52,7 @@ mrb_class(mrb_state *mrb, mrb_value v) ...@@ -52,6 +52,7 @@ mrb_class(mrb_state *mrb, mrb_value v)
} }
// TODO: figure out where to put user flags // 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_PREPENDED (1 << 19)
#define MRB_FLAG_IS_ORIGIN (1 << 20) #define MRB_FLAG_IS_ORIGIN (1 << 20)
#define MRB_CLASS_ORIGIN(c) do {\ #define MRB_CLASS_ORIGIN(c) do {\
......
...@@ -22,6 +22,10 @@ struct RBasic { ...@@ -22,6 +22,10 @@ struct RBasic {
}; };
#define mrb_basic_ptr(v) ((struct RBasic*)(mrb_ptr(v))) #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 { struct RObject {
MRB_OBJECT_HEADER; MRB_OBJECT_HEADER;
struct iv_tbl *iv; struct iv_tbl *iv;
......
...@@ -62,10 +62,6 @@ struct RString { ...@@ -62,10 +62,6 @@ struct RString {
#define RSTR_SET_NOFREE_FLAG(s) ((s)->flags |= MRB_STR_NOFREE) #define RSTR_SET_NOFREE_FLAG(s) ((s)->flags |= MRB_STR_NOFREE)
#define RSTR_UNSET_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 * Returns a pointer from a Ruby string
*/ */
...@@ -80,7 +76,6 @@ MRB_API mrb_int mrb_str_strlen(mrb_state*, struct RString*); ...@@ -80,7 +76,6 @@ MRB_API mrb_int mrb_str_strlen(mrb_state*, struct RString*);
#define MRB_STR_SHARED 1 #define MRB_STR_SHARED 1
#define MRB_STR_NOFREE 2 #define MRB_STR_NOFREE 2
#define MRB_STR_FROZEN 4
#define MRB_STR_NO_UTF 8 #define MRB_STR_NO_UTF 8
#define MRB_STR_EMBED 16 #define MRB_STR_EMBED 16
#define MRB_STR_EMBED_LEN_MASK 0x3e0 #define MRB_STR_EMBED_LEN_MASK 0x3e0
......
...@@ -108,6 +108,10 @@ ary_fill_with_nil(mrb_value *ptr, mrb_int size) ...@@ -108,6 +108,10 @@ ary_fill_with_nil(mrb_value *ptr, mrb_int size)
static void static void
ary_modify(mrb_state *mrb, struct RArray *a) 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)) { if (ARY_SHARED_P(a)) {
mrb_shared_array *shared = a->aux.shared; mrb_shared_array *shared = a->aux.shared;
......
...@@ -98,9 +98,9 @@ static void mrb_hash_modify(mrb_state *mrb, mrb_value hash); ...@@ -98,9 +98,9 @@ static void mrb_hash_modify(mrb_state *mrb, mrb_value hash);
static inline mrb_value static inline mrb_value
mrb_hash_ht_key(mrb_state *mrb, mrb_value key) 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); key = mrb_str_dup(mrb, key);
RSTR_SET_FROZEN_FLAG(mrb_str_ptr(key)); RBASIC_SET_FROZEN_FLAG(mrb_str_ptr(key));
} }
return key; return key;
} }
...@@ -278,6 +278,9 @@ mrb_hash_tbl(mrb_state *mrb, mrb_value hash) ...@@ -278,6 +278,9 @@ mrb_hash_tbl(mrb_state *mrb, mrb_value hash)
static void static void
mrb_hash_modify(mrb_state *mrb, mrb_value hash) 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); mrb_hash_tbl(mrb, hash);
} }
......
...@@ -450,6 +450,15 @@ mrb_obj_extend_m(mrb_state *mrb, mrb_value self) ...@@ -450,6 +450,15 @@ mrb_obj_extend_m(mrb_state *mrb, mrb_value self)
return mrb_obj_extend(mrb, argc, argv, 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 */ /* 15.3.1.3.15 */
/* /*
* call-seq: * call-seq:
...@@ -1124,6 +1133,7 @@ mrb_init_kernel(mrb_state *mrb) ...@@ -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, "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, "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, "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, "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, "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 */ mrb_define_method(mrb, krn, "initialize_copy", mrb_obj_init_copy, MRB_ARGS_REQ(1)); /* 15.3.1.3.16 */
......
...@@ -501,7 +501,7 @@ str_index(mrb_state *mrb, mrb_value str, mrb_value sub, mrb_int offset) ...@@ -501,7 +501,7 @@ str_index(mrb_state *mrb, mrb_value str, mrb_value sub, mrb_int offset)
static void static void
check_frozen(mrb_state *mrb, struct RString *s) 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"); mrb_raise(mrb, E_RUNTIME_ERROR, "can't modify frozen string");
} }
} }
...@@ -700,15 +700,6 @@ mrb_str_modify(mrb_state *mrb, struct RString *s) ...@@ -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_API mrb_value
mrb_str_resize(mrb_state *mrb, mrb_value str, mrb_int len) 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) ...@@ -2217,7 +2208,7 @@ mrb_string_value_cstr(mrb_state *mrb, mrb_value *ptr)
char *p = RSTR_PTR(ps); char *p = RSTR_PTR(ps);
if (!p || p[len] != '\0') { if (!p || p[len] != '\0') {
if (RSTR_FROZEN_P(ps)) { if (RBASIC_FROZEN_P(ps)) {
*ptr = str = mrb_str_dup(mrb, str); *ptr = str = mrb_str_dup(mrb, str);
ps = mrb_str_ptr(str); ps = mrb_str_ptr(str);
} }
...@@ -2746,8 +2737,6 @@ mrb_init_string(mrb_state *mrb) ...@@ -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, "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, "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, "bytes", mrb_str_bytes, MRB_ARGS_NONE());
mrb_define_method(mrb, s, "freeze", mrb_str_freeze, MRB_ARGS_NONE());
} }
/* /*
......
...@@ -373,3 +373,10 @@ assert("Array#rindex") do ...@@ -373,3 +373,10 @@ assert("Array#rindex") do
$a = [2, 3, 4, 5, 6, 7, 8, 9, 10, Sneaky.new] $a = [2, 3, 4, 5, 6, 7, 8, 9, 10, Sneaky.new]
assert_equal 0, $a.rindex(1) assert_equal 0, $a.rindex(1)
end end
assert('Array#freeze') do
a = [].freeze
assert_raise(RuntimeError) do
a[0] = 1
end
end
...@@ -366,3 +366,10 @@ assert('Hash#rehash') do ...@@ -366,3 +366,10 @@ assert('Hash#rehash') do
h.rehash h.rehash
assert_equal("b", h[[:b]]) assert_equal("b", h[[:b]])
end end
assert('Hash#freeze') do
h = {}.freeze
assert_raise(RuntimeError) do
h[:a] = 'b'
end
end
...@@ -257,6 +257,11 @@ assert('Kernel#extend works on toplevel', '15.3.1.3.13') do ...@@ -257,6 +257,11 @@ assert('Kernel#extend works on toplevel', '15.3.1.3.13') do
assert_true respond_to?(:test_method) assert_true respond_to?(:test_method)
end 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('Kernel#global_variables', '15.3.1.3.14') do
assert_equal Array, global_variables.class assert_equal Array, global_variables.class
end end
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment