summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorYukihiro "Matz" Matsumoto <[email protected]>2014-09-02 16:41:38 +0900
committerYukihiro "Matz" Matsumoto <[email protected]>2014-09-02 16:41:38 +0900
commit90ba47ccfe67859e3f139199da33e89137a74a41 (patch)
tree8f9781696a2694697e762224509dbbb1c06475f2
parent6c7b0d88e87a41b6e2c908e0a9dcbc722b7553dc (diff)
downloadmruby-90ba47ccfe67859e3f139199da33e89137a74a41.tar.gz
mruby-90ba47ccfe67859e3f139199da33e89137a74a41.zip
implement attr_reader and attr_writer in C; use cfunc closure to speed-up
-rw-r--r--mrblib/class.rb25
-rw-r--r--src/class.c107
2 files changed, 98 insertions, 34 deletions
diff --git a/mrblib/class.rb b/mrblib/class.rb
index ebb44ca4c..39e0d5091 100644
--- a/mrblib/class.rb
+++ b/mrblib/class.rb
@@ -1,28 +1,5 @@
class Module
- # 15.2.2.4.13
- def attr_reader(*names)
- names.each do |name|
- name = name.to_s
- raise(NameError, "#{name.inspect} is not allowed as an instance variable name") if name.include?('@') || name.include?('?') || name.include?('$')
-
- attr_name = '@'+name
- define_method(name){self.instance_variable_get(attr_name)}
- end
- nil
- end
- # 15.2.2.4.14
- def attr_writer(*names)
- names.each do |name|
- name = name.to_s
- raise(NameError, "#{name.inspect} is not allowed as an instance variable name") if name.include?('@') || name.include?('?') || name.include?('$')
-
- attr_name = '@'+name
- name = (name+"=").intern
- define_method(name){|v|self.instance_variable_set(attr_name,v)}
- end
- nil
- end
- # 15.2.2.4.12
+ # 15.2.2.4.12
def attr_accessor(*names)
attr_reader(*names)
attr_writer(*names)
diff --git a/src/class.c b/src/class.c
index 91ee711bc..b7da56514 100644
--- a/src/class.c
+++ b/src/class.c
@@ -393,6 +393,21 @@ to_hash(mrb_state *mrb, mrb_value val)
return check_type(mrb, val, MRB_TT_HASH, "Hash", "to_hash");
}
+static mrb_sym
+to_sym(mrb_state *mrb, mrb_value ss)
+{
+ if (mrb_type(ss) == MRB_TT_SYMBOL) {
+ return mrb_symbol(ss);
+ }
+ else if (mrb_string_p(ss)) {
+ return mrb_intern_str(mrb, to_str(mrb, ss));
+ }
+ else {
+ mrb_value obj = mrb_funcall(mrb, ss, "inspect", 0);
+ mrb_raisef(mrb, E_TYPE_ERROR, "%S is not a symbol", obj);
+ }
+}
+
/*
retrieve arguments from mrb_state.
@@ -635,16 +650,7 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
mrb_value ss;
ss = *sp++;
- if (mrb_type(ss) == MRB_TT_SYMBOL) {
- *symp = mrb_symbol(ss);
- }
- else if (mrb_string_p(ss)) {
- *symp = mrb_intern_str(mrb, to_str(mrb, ss));
- }
- else {
- mrb_value obj = mrb_funcall(mrb, ss, "inspect", 0);
- mrb_raisef(mrb, E_TYPE_ERROR, "%S is not a symbol", obj);
- }
+ *symp = to_sym(mrb, ss);
i++;
}
}
@@ -1051,6 +1057,85 @@ mrb_method_search(mrb_state *mrb, struct RClass* c, mrb_sym mid)
}
static mrb_value
+attr_reader(mrb_state *mrb, mrb_value obj)
+{
+ mrb_value name = mrb_proc_cfunc_env_get(mrb, 0);
+ return mrb_iv_get(mrb, obj, to_sym(mrb, name));
+}
+
+static mrb_value
+mrb_mod_attr_reader(mrb_state *mrb, mrb_value mod)
+{
+ struct RClass *c = mrb_class_ptr(mod);
+ mrb_value *argv;
+ mrb_int argc, i;
+
+ mrb_get_args(mrb, "*", &argv, &argc);
+ for (i=0; i<argc; i++) {
+ mrb_value name, str;
+ mrb_sym method, sym;
+
+ method = to_sym(mrb, argv[i]);
+ name = mrb_sym2str(mrb, method);
+ str = mrb_str_buf_new(mrb, RSTRING_LEN(name)+1);
+ mrb_str_cat_cstr(mrb, str, "@");
+ mrb_str_cat_str(mrb, str, name);
+ sym = mrb_intern_str(mrb, str);
+ mrb_iv_check(mrb, sym);
+ name = mrb_symbol_value(sym);
+ mrb_define_method_raw(mrb, c, method,
+ mrb_proc_new_cfunc_with_env(mrb, attr_reader, 1, &name));
+ }
+ return mrb_nil_value();
+}
+
+static mrb_value
+attr_writer(mrb_state *mrb, mrb_value obj)
+{
+ mrb_value name = mrb_proc_cfunc_env_get(mrb, 0);
+ mrb_value val;
+
+ mrb_get_args(mrb, "o", &val);
+ mrb_iv_set(mrb, obj, to_sym(mrb, name), val);
+ return val;
+}
+
+static mrb_value
+mrb_mod_attr_writer(mrb_state *mrb, mrb_value mod)
+{
+ struct RClass *c = mrb_class_ptr(mod);
+ mrb_value *argv;
+ mrb_int argc, i;
+
+ mrb_get_args(mrb, "*", &argv, &argc);
+ for (i=0; i<argc; i++) {
+ mrb_value name, str, attr;
+ mrb_sym method, sym;
+
+ method = to_sym(mrb, argv[i]);
+
+ /* prepare iv name (@name) */
+ name = mrb_sym2str(mrb, method);
+ str = mrb_str_buf_new(mrb, RSTRING_LEN(name)+1);
+ mrb_str_cat_cstr(mrb, str, "@");
+ mrb_str_cat_str(mrb, str, name);
+ sym = mrb_intern_str(mrb, str);
+ mrb_iv_check(mrb, sym);
+ attr = mrb_symbol_value(sym);
+
+ /* prepare method name (name=) */
+ str = mrb_str_buf_new(mrb, RSTRING_LEN(str));
+ mrb_str_cat_str(mrb, str, name);
+ mrb_str_cat_cstr(mrb, str, "=");
+ method = mrb_intern_str(mrb, str);
+
+ mrb_define_method_raw(mrb, c, method,
+ mrb_proc_new_cfunc_with_env(mrb, attr_writer, 1, &attr));
+ }
+ return mrb_nil_value();
+}
+
+static mrb_value
mrb_instance_alloc(mrb_state *mrb, mrb_value cv)
{
struct RClass *c = mrb_class_ptr(cv);
@@ -2033,6 +2118,8 @@ mrb_init_class(mrb_state *mrb)
mrb_define_method(mrb, mod, "public", mrb_mod_dummy_visibility, MRB_ARGS_ANY()); /* 15.2.2.4.38 */
mrb_define_method(mrb, mod, "remove_class_variable", mrb_mod_remove_cvar, MRB_ARGS_REQ(1)); /* 15.2.2.4.39 */
mrb_define_method(mrb, mod, "remove_method", mrb_mod_remove_method, MRB_ARGS_ANY()); /* 15.2.2.4.41 */
+ mrb_define_method(mrb, mod, "attr_reader", mrb_mod_attr_reader, MRB_ARGS_ANY()); /* 15.2.2.4.13 */
+ mrb_define_method(mrb, mod, "attr_writer", mrb_mod_attr_writer, MRB_ARGS_ANY()); /* 15.2.2.4.14 */
mrb_define_method(mrb, mod, "to_s", mrb_mod_to_s, MRB_ARGS_NONE());
mrb_define_method(mrb, mod, "inspect", mrb_mod_to_s, MRB_ARGS_NONE());
mrb_define_method(mrb, mod, "alias_method", mrb_mod_alias, MRB_ARGS_ANY()); /* 15.2.2.4.8 */