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)
}
// 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 {\
......
......@@ -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;
......
......@@ -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
......
......@@ -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;
......
......@@ -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);
}
......
......@@ -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 */
......
......@@ -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());
}
/*
......
......@@ -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
......@@ -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
......@@ -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
......
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