diff options
| author | Hiroshi Mimaki <[email protected]> | 2019-10-18 14:46:03 +0900 |
|---|---|---|
| committer | Hiroshi Mimaki <[email protected]> | 2019-10-18 14:46:03 +0900 |
| commit | b6546835457d1935a9c77965686b2a1256874d96 (patch) | |
| tree | 724cfd71a7c956b0648e8c58f3717d797fff5f29 /src/class.c | |
| parent | 8ee516436b8d174a50764939bee23a442aa00b3f (diff) | |
| parent | 20d01f118ddb7e7f2f36926a7a3db35573611857 (diff) | |
| download | mruby-b6546835457d1935a9c77965686b2a1256874d96.tar.gz mruby-b6546835457d1935a9c77965686b2a1256874d96.zip | |
Merge master.
Diffstat (limited to 'src/class.c')
| -rw-r--r-- | src/class.c | 654 |
1 files changed, 374 insertions, 280 deletions
diff --git a/src/class.c b/src/class.c index 5c5ee9d17..b1c7513de 100644 --- a/src/class.c +++ b/src/class.c @@ -7,6 +7,7 @@ #include <stdarg.h> #include <mruby.h> #include <mruby/array.h> +#include <mruby/hash.h> #include <mruby/class.h> #include <mruby/numeric.h> #include <mruby/proc.h> @@ -15,6 +16,7 @@ #include <mruby/error.h> #include <mruby/data.h> #include <mruby/istruct.h> +#include <mruby/opcode.h> KHASH_DEFINE(mt, mrb_sym, mrb_method_t, TRUE, kh_int_hash_func, kh_int_hash_equal) @@ -63,18 +65,31 @@ mrb_class_name_class(mrb_state *mrb, struct RClass *outer, struct RClass *c, mrb name = mrb_symbol_value(id); } else { - name = mrb_class_path(mrb, outer); - if (mrb_nil_p(name)) { /* unnamed outer class */ + const char *n; + mrb_int len; + mrb_value outer_name = mrb_class_path(mrb, outer); + + if (mrb_nil_p(outer_name)) { /* unnamed outer class */ if (outer != mrb->object_class && outer != c) { - mrb_obj_iv_set(mrb, (struct RObject*)c, mrb_intern_lit(mrb, "__outer__"), - mrb_obj_value(outer)); + mrb_obj_iv_set_force(mrb, (struct RObject*)c, mrb_intern_lit(mrb, "__outer__"), + mrb_obj_value(outer)); } return; } - mrb_str_cat_cstr(mrb, name, "::"); - mrb_str_cat_cstr(mrb, name, mrb_sym2name(mrb, id)); + n = mrb_sym_name_len(mrb, id, &len); + name = mrb_str_new_capa(mrb, RSTRING_LEN(outer_name) + 2 + len); + mrb_str_cat_str(mrb, name, outer_name); + mrb_str_cat_lit(mrb, name, "::"); + mrb_str_cat(mrb, name, n, len); + MRB_SET_FROZEN_FLAG(mrb_obj_ptr(name)); } - mrb_obj_iv_set(mrb, (struct RObject*)c, nsym, name); + mrb_obj_iv_set_force(mrb, (struct RObject*)c, nsym, name); +} + +mrb_bool +mrb_const_name_p(mrb_state *mrb, const char *name, mrb_int len) +{ + return len > 0 && ISUPPER(name[0]) && mrb_ident_p(name+1, len-1); } static void @@ -120,6 +135,7 @@ prepare_singleton_class(mrb_state *mrb, struct RBasic *o) mrb_field_write_barrier(mrb, (struct RBasic*)o, (struct RBasic*)sc); mrb_field_write_barrier(mrb, (struct RBasic*)sc, (struct RBasic*)o); mrb_obj_iv_set(mrb, (struct RObject*)sc, mrb_intern_lit(mrb, "__attached__"), mrb_obj_value(o)); + sc->flags |= o->flags & MRB_FL_OBJ_IS_FROZEN; } static mrb_value @@ -170,7 +186,7 @@ static void check_if_class_or_module(mrb_state *mrb, mrb_value obj) { if (!class_ptr_p(obj)) { - mrb_raisef(mrb, E_TYPE_ERROR, "%S is not a class/module", mrb_inspect(mrb, obj)); + mrb_raisef(mrb, E_TYPE_ERROR, "%!v is not a class/module", obj); } } @@ -200,15 +216,15 @@ mrb_define_module(mrb_state *mrb, const char *name) return define_module(mrb, mrb_intern_cstr(mrb, name), mrb->object_class); } -MRB_API struct RClass* +struct RClass* mrb_vm_define_module(mrb_state *mrb, mrb_value outer, mrb_sym id) { check_if_class_or_module(mrb, outer); if (mrb_const_defined_at(mrb, outer, id)) { mrb_value old = mrb_const_get(mrb, outer, id); - if (mrb_type(old) != MRB_TT_MODULE) { - mrb_raisef(mrb, E_TYPE_ERROR, "%S is not a module", mrb_inspect(mrb, old)); + if (!mrb_module_p(old)) { + mrb_raisef(mrb, E_TYPE_ERROR, "%!v is not a module", old); } return mrb_class_ptr(old); } @@ -241,9 +257,8 @@ define_class(mrb_state *mrb, mrb_sym name, struct RClass *super, struct RClass * c = class_from_sym(mrb, outer, name); MRB_CLASS_ORIGIN(c); if (super && mrb_class_real(c->super) != super) { - mrb_raisef(mrb, E_TYPE_ERROR, "superclass mismatch for Class %S (%S not %S)", - mrb_sym2str(mrb, name), - mrb_obj_value(c->super), mrb_obj_value(super)); + mrb_raisef(mrb, E_TYPE_ERROR, "superclass mismatch for Class %n (%C not %C)", + name, c->super, super); } return c; } @@ -258,7 +273,7 @@ MRB_API struct RClass* mrb_define_class_id(mrb_state *mrb, mrb_sym name, struct RClass *super) { if (!super) { - mrb_warn(mrb, "no super class for '%S', Object assumed", mrb_sym2str(mrb, name)); + mrb_warn(mrb, "no super class for '%n', Object assumed", name); } return define_class(mrb, name, super, mrb->object_class); } @@ -298,16 +313,15 @@ mrb_class_inherited(mrb_state *mrb, struct RClass *super, struct RClass *klass) } } -MRB_API struct RClass* +struct RClass* mrb_vm_define_class(mrb_state *mrb, mrb_value outer, mrb_value super, mrb_sym id) { struct RClass *s; struct RClass *c; if (!mrb_nil_p(super)) { - if (mrb_type(super) != MRB_TT_CLASS) { - mrb_raisef(mrb, E_TYPE_ERROR, "superclass must be a Class (%S given)", - mrb_inspect(mrb, super)); + if (!mrb_class_p(super)) { + mrb_raisef(mrb, E_TYPE_ERROR, "superclass must be a Class (%!v given)", super); } s = mrb_class_ptr(super); } @@ -318,14 +332,14 @@ mrb_vm_define_class(mrb_state *mrb, mrb_value outer, mrb_value super, mrb_sym id if (mrb_const_defined_at(mrb, outer, id)) { mrb_value old = mrb_const_get(mrb, outer, id); - if (mrb_type(old) != MRB_TT_CLASS) { - mrb_raisef(mrb, E_TYPE_ERROR, "%S is not a class", mrb_inspect(mrb, old)); + if (!mrb_class_p(old)) { + mrb_raisef(mrb, E_TYPE_ERROR, "%!v is not a class", old); } c = mrb_class_ptr(old); if (s) { /* check super class */ if (mrb_class_real(c->super) != s) { - mrb_raisef(mrb, E_TYPE_ERROR, "superclass mismatch for class %S", old); + mrb_raisef(mrb, E_TYPE_ERROR, "superclass mismatch for class %v", old); } } return c; @@ -375,7 +389,7 @@ mrb_exc_get(mrb_state *mrb, const char *name) mrb_value c = mrb_const_get(mrb, mrb_obj_value(mrb->object_class), mrb_intern_cstr(mrb, name)); - if (mrb_type(c) != MRB_TT_CLASS) { + if (!mrb_class_p(c)) { mrb_raise(mrb, mrb->eException_class, "exception corrupted"); } exc = e = mrb_class_ptr(c); @@ -403,7 +417,7 @@ mrb_module_get(mrb_state *mrb, const char *name) /*! * Defines a class under the namespace of \a outer. * \param outer a class which contains the new class. - * \param id name of the new class + * \param name name of the new class * \param super a class from which the new class will derive. * NULL means \c Object class. * \return the created class @@ -424,8 +438,7 @@ mrb_define_class_under(mrb_state *mrb, struct RClass *outer, const char *name, s #if 0 if (!super) { - mrb_warn(mrb, "no super class for '%S::%S', Object assumed", - mrb_obj_value(outer), mrb_sym2str(mrb, id)); + mrb_warn(mrb, "no super class for '%C::%n', Object assumed", outer, id); } #endif c = define_class(mrb, id, super, outer); @@ -441,12 +454,7 @@ mrb_define_method_raw(mrb_state *mrb, struct RClass *c, mrb_sym mid, mrb_method_ MRB_CLASS_ORIGIN(c); h = c->mt; - if (MRB_FROZEN_P(c)) { - if (c->tt == MRB_TT_MODULE) - mrb_raise(mrb, E_FROZEN_ERROR, "can't modify frozen module"); - else - mrb_raise(mrb, E_FROZEN_ERROR, "can't modify frozen class"); - } + mrb_check_frozen(mrb, c); if (!h) h = c->mt = kh_init(mt, mrb); k = kh_put(mt, mrb, h, mid); kh_value(h, k) = m; @@ -470,6 +478,9 @@ mrb_define_method_id(mrb_state *mrb, struct RClass *c, mrb_sym mid, mrb_func_t f int ai = mrb_gc_arena_save(mrb); MRB_METHOD_FROM_FUNC(m, func); + if (aspec == MRB_ARGS_NONE()) { + MRB_METHOD_NOARG_SET(m); + } mrb_define_method_raw(mrb, c, mid, m); mrb_gc_arena_restore(mrb, ai); } @@ -487,8 +498,7 @@ mrb_notimplement(mrb_state *mrb) mrb_callinfo *ci = mrb->c->ci; if (ci->mid) { - mrb_value str = mrb_sym2str(mrb, ci->mid); - mrb_raisef(mrb, E_NOTIMP_ERROR, "%S() function is unimplemented on this machine", str); + mrb_raisef(mrb, E_NOTIMP_ERROR, "%n() function is unimplemented on this machine", ci->mid); } } @@ -501,30 +511,17 @@ mrb_notimplement_m(mrb_state *mrb, mrb_value self) return mrb_nil_value(); } -#define CHECK_TYPE(mrb, val, t, c) do { \ - if (mrb_type(val) != (t)) {\ - mrb_raisef(mrb, E_TYPE_ERROR, "expected %S", mrb_str_new_lit(mrb, c));\ - }\ -} while (0) - -static mrb_value -to_str(mrb_state *mrb, mrb_value val) -{ - CHECK_TYPE(mrb, val, MRB_TT_STRING, "String"); - return val; -} - static mrb_value to_ary(mrb_state *mrb, mrb_value val) { - CHECK_TYPE(mrb, val, MRB_TT_ARRAY, "Array"); + mrb_check_type(mrb, val, MRB_TT_ARRAY); return val; } static mrb_value to_hash(mrb_state *mrb, mrb_value val) { - CHECK_TYPE(mrb, val, MRB_TT_HASH, "Hash"); + mrb_check_type(mrb, val, MRB_TT_HASH); return val; } @@ -559,6 +556,8 @@ mrb_get_argv(mrb_state *mrb) return array_argv; } +void mrb_hash_check_kdict(mrb_state *mrb, mrb_value self); + /* retrieve arguments from mrb_state. @@ -571,23 +570,24 @@ mrb_get_argv(mrb_state *mrb) string mruby type C type note ---------------------------------------------------------------------------------------------- o: Object [mrb_value] - C: class/module [mrb_value] + C: Class/Module [mrb_value] S: String [mrb_value] when ! follows, the value may be nil A: Array [mrb_value] when ! follows, the value may be nil H: Hash [mrb_value] when ! follows, the value may be nil s: String [char*,mrb_int] Receive two arguments; s! gives (NULL,0) for nil z: String [char*] NUL terminated string; z! gives NULL for nil a: Array [mrb_value*,mrb_int] Receive two arguments; a! gives (NULL,0) for nil - f: Float [mrb_float] - i: Integer [mrb_int] - 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] &! raises exception if no block given + f: Fixnum/Float [mrb_float] + i: Fixnum/Float [mrb_int] + b: boolean [mrb_bool] + n: String/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; when ! follows, the value may be nil + I: inline struct [void*] + &: block [mrb_value] &! raises exception if no block given *: rest argument [mrb_value*,mrb_int] The rest of the arguments as an array; *! avoid copy of the stack |: optional Following arguments are optional ?: optional given [mrb_bool] true if preceding argument (optional) is given + ':': keyword args [mrb_kwargs const] Get keyword arguments */ MRB_API mrb_int mrb_get_args(mrb_state *mrb, const char *format, ...) @@ -602,6 +602,9 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) mrb_bool opt = FALSE; mrb_bool opt_skip = TRUE; mrb_bool given = TRUE; + mrb_value kdict; + mrb_bool reqkarg = FALSE; + mrb_int needargc = 0; va_start(ap, format); @@ -615,23 +618,39 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) break; case '*': opt_skip = FALSE; + if (!reqkarg) reqkarg = strchr(fmt, ':') ? TRUE : FALSE; goto check_exit; case '!': break; case '&': case '?': if (opt) opt_skip = FALSE; break; + case ':': + reqkarg = TRUE; + break; default: + if (!opt) needargc ++; break; } } check_exit: + if (reqkarg && argc > needargc && mrb_hash_p(kdict = ARGV[argc - 1])) { + mrb_hash_check_kdict(mrb, kdict); + argc --; + } + else { + kdict = mrb_nil_value(); + } + opt = FALSE; i = 0; while ((c = *format++)) { + mrb_value *argv = ARGV; + mrb_bool altmode; + switch (c) { - case '|': case '*': case '&': case '?': + case '|': case '*': case '&': case '?': case ':': break; default: if (argc <= i) { @@ -645,6 +664,14 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) break; } + if (*format == '!') { + format ++; + altmode = TRUE; + } + else { + altmode = FALSE; + } + switch (c) { case 'o': { @@ -652,7 +679,7 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) p = va_arg(ap, mrb_value*); if (i < argc) { - *p = ARGV[arg_i++]; + *p = argv[arg_i++]; i++; } } @@ -665,9 +692,9 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) if (i < argc) { mrb_value ss; - ss = ARGV[arg_i++]; + ss = argv[arg_i++]; if (!class_ptr_p(ss)) { - mrb_raisef(mrb, E_TYPE_ERROR, "%S is not class/module", ss); + mrb_raisef(mrb, E_TYPE_ERROR, "%v is not class/module", ss); } *p = ss; i++; @@ -679,17 +706,12 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) mrb_value *p; p = va_arg(ap, mrb_value*); - if (*format == '!') { - format++; - if (i < argc && mrb_nil_p(ARGV[arg_i])) { - *p = ARGV[arg_i++]; - i++; - break; - } - } if (i < argc) { - *p = to_str(mrb, ARGV[arg_i++]); + *p = argv[arg_i++]; i++; + if (!(altmode && mrb_nil_p(*p))) { + mrb_to_str(mrb, *p); + } } } break; @@ -698,17 +720,12 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) mrb_value *p; p = va_arg(ap, mrb_value*); - if (*format == '!') { - format++; - if (i < argc && mrb_nil_p(ARGV[arg_i])) { - *p = ARGV[arg_i++]; - i++; - break; - } - } if (i < argc) { - *p = to_ary(mrb, ARGV[arg_i++]); + *p = argv[arg_i++]; i++; + if (!(altmode && mrb_nil_p(*p))) { + *p = to_ary(mrb, *p); + } } } break; @@ -717,17 +734,12 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) mrb_value *p; p = va_arg(ap, mrb_value*); - if (*format == '!') { - format++; - if (i < argc && mrb_nil_p(ARGV[arg_i])) { - *p = ARGV[arg_i++]; - i++; - break; - } - } if (i < argc) { - *p = to_hash(mrb, ARGV[arg_i++]); + *p = argv[arg_i++]; i++; + if (!(altmode && mrb_nil_p(*p))) { + *p = to_hash(mrb, *p); + } } } break; @@ -739,20 +751,18 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) ps = va_arg(ap, char**); pl = va_arg(ap, mrb_int*); - if (*format == '!') { - format++; - if (i < argc && mrb_nil_p(ARGV[arg_i])) { + if (i < argc) { + ss = argv[arg_i++]; + i++; + if (altmode && mrb_nil_p(ss)) { *ps = NULL; *pl = 0; - i++; arg_i++; - break; } - } - if (i < argc) { - ss = to_str(mrb, ARGV[arg_i++]); - *ps = RSTRING_PTR(ss); - *pl = RSTRING_LEN(ss); - i++; + else { + mrb_to_str(mrb, ss); + *ps = RSTRING_PTR(ss); + *pl = RSTRING_LEN(ss); + } } } break; @@ -762,18 +772,16 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) const char **ps; ps = va_arg(ap, const char**); - if (*format == '!') { - format++; - if (i < argc && mrb_nil_p(ARGV[arg_i])) { - *ps = NULL; - i++; arg_i++; - break; - } - } if (i < argc) { - ss = to_str(mrb, ARGV[arg_i++]); - *ps = mrb_string_value_cstr(mrb, &ss); + ss = argv[arg_i++]; i++; + if (altmode && mrb_nil_p(ss)) { + *ps = NULL; + } + else { + mrb_to_str(mrb, ss); + *ps = RSTRING_CSTR(mrb, ss); + } } } break; @@ -786,21 +794,19 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) pb = va_arg(ap, mrb_value**); pl = va_arg(ap, mrb_int*); - if (*format == '!') { - format++; - if (i < argc && mrb_nil_p(ARGV[arg_i])) { + if (i < argc) { + aa = argv[arg_i++]; + i++; + if (altmode && mrb_nil_p(aa)) { *pb = 0; *pl = 0; - i++; arg_i++; - break; } - } - if (i < argc) { - aa = to_ary(mrb, ARGV[arg_i++]); - a = mrb_ary_ptr(aa); - *pb = ARY_PTR(a); - *pl = ARY_LEN(a); - i++; + else { + aa = to_ary(mrb, aa); + a = mrb_ary_ptr(aa); + *pb = ARY_PTR(a); + *pl = ARY_LEN(a); + } } } break; @@ -811,10 +817,10 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) p = va_arg(ap, void**); if (i < argc) { - ss = ARGV[arg_i]; - if (mrb_type(ss) != MRB_TT_ISTRUCT) + ss = argv[arg_i]; + if (!mrb_istruct_p(ss)) { - mrb_raisef(mrb, E_TYPE_ERROR, "%S is not inline struct", ss); + mrb_raisef(mrb, E_TYPE_ERROR, "%v is not inline struct", ss); } *p = mrb_istruct_ptr(ss); arg_i++; @@ -829,7 +835,7 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) p = va_arg(ap, mrb_float*); if (i < argc) { - *p = mrb_to_flo(mrb, ARGV[arg_i]); + *p = mrb_to_flo(mrb, argv[arg_i]); arg_i++; i++; } @@ -842,29 +848,7 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) p = va_arg(ap, mrb_int*); if (i < argc) { - switch (mrb_type(ARGV[arg_i])) { - case MRB_TT_FIXNUM: - *p = mrb_fixnum(ARGV[arg_i]); - break; -#ifndef MRB_WITHOUT_FLOAT - case MRB_TT_FLOAT: - { - mrb_float f = mrb_float(ARGV[arg_i]); - - if (!FIXABLE_FLOAT(f)) { - mrb_raise(mrb, E_RANGE_ERROR, "float too big for int"); - } - *p = (mrb_int)f; - } - break; -#endif - case MRB_TT_STRING: - mrb_raise(mrb, E_TYPE_ERROR, "no implicit conversion of String into Integer"); - break; - default: - *p = mrb_fixnum(mrb_Integer(mrb, ARGV[arg_i])); - break; - } + *p = mrb_fixnum(mrb_to_int(mrb, argv[arg_i])); arg_i++; i++; } @@ -875,7 +859,7 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) mrb_bool *boolp = va_arg(ap, mrb_bool*); if (i < argc) { - mrb_value b = ARGV[arg_i++]; + mrb_value b = argv[arg_i++]; *boolp = mrb_test(b); i++; } @@ -889,7 +873,7 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) if (i < argc) { mrb_value ss; - ss = ARGV[arg_i++]; + ss = argv[arg_i++]; *symp = to_sym(mrb, ss); i++; } @@ -902,17 +886,15 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) datap = va_arg(ap, void**); type = va_arg(ap, struct mrb_data_type const*); - if (*format == '!') { - format++; - if (i < argc && mrb_nil_p(ARGV[arg_i])) { + if (i < argc) { + mrb_value dd = argv[arg_i++]; + i++; + if (altmode && mrb_nil_p(dd)) { *datap = 0; - i++; arg_i++; - break; } - } - if (i < argc) { - *datap = mrb_data_get_ptr(mrb, ARGV[arg_i++], type); - ++i; + else { + *datap = mrb_data_get_ptr(mrb, dd, type); + } } } break; @@ -928,11 +910,8 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) else { bp = mrb->c->stack + mrb->c->ci->argc + 1; } - if (*format == '!') { - format ++; - if (mrb_nil_p(*bp)) { - mrb_raise(mrb, E_ARGUMENT_ERROR, "no block given"); - } + if (altmode && mrb_nil_p(*bp)) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "no block given"); } *p = *bp; } @@ -954,22 +933,18 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) { mrb_value **var; mrb_int *pl; - mrb_bool nocopy = array_argv ? TRUE : FALSE; + mrb_bool nocopy = altmode || array_argv ? TRUE : FALSE; - if (*format == '!') { - format++; - nocopy = TRUE; - } var = va_arg(ap, mrb_value**); pl = va_arg(ap, mrb_int*); if (argc > i) { *pl = argc-i; if (*pl > 0) { if (nocopy) { - *var = ARGV+arg_i; + *var = argv+arg_i; } else { - mrb_value args = mrb_ary_new_from_values(mrb, *pl, ARGV+arg_i); + mrb_value args = mrb_ary_new_from_values(mrb, *pl, argv+arg_i); RARRAY(args)->c = NULL; *var = RARRAY_PTR(args); } @@ -983,8 +958,64 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) } } break; + + case ':': + { + mrb_value ksrc = mrb_hash_p(kdict) ? mrb_hash_dup(mrb, kdict) : mrb_hash_new(mrb); + const mrb_kwargs *kwargs = va_arg(ap, const mrb_kwargs*); + mrb_value *rest; + + if (kwargs == NULL) { + rest = NULL; + } + else { + uint32_t kwnum = kwargs->num; + uint32_t required = kwargs->required; + const char *const *kname = kwargs->table; + mrb_value *values = kwargs->values; + uint32_t j; + const uint32_t keyword_max = 40; + + if (kwnum > keyword_max || required > kwnum) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "keyword number is too large"); + } + + for (j = required; j > 0; j --, kname ++, values ++) { + mrb_value k = mrb_symbol_value(mrb_intern_cstr(mrb, *kname)); + if (!mrb_hash_key_p(mrb, ksrc, k)) { + mrb_raisef(mrb, E_ARGUMENT_ERROR, "missing keyword: %s", *kname); + } + *values = mrb_hash_delete_key(mrb, ksrc, k); + mrb_gc_protect(mrb, *values); + } + + for (j = kwnum - required; j > 0; j --, kname ++, values ++) { + mrb_value k = mrb_symbol_value(mrb_intern_cstr(mrb, *kname)); + if (mrb_hash_key_p(mrb, ksrc, k)) { + *values = mrb_hash_delete_key(mrb, ksrc, k); + mrb_gc_protect(mrb, *values); + } + else { + *values = mrb_undef_value(); + } + } + + rest = kwargs->rest; + } + + if (rest) { + *rest = ksrc; + } + else if (!mrb_hash_empty_p(mrb, ksrc)) { + ksrc = mrb_hash_keys(mrb, ksrc); + ksrc = RARRAY_PTR(ksrc)[0]; + mrb_raisef(mrb, E_ARGUMENT_ERROR, "unknown keyword: %v", ksrc); + } + } + break; + default: - mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid argument specifier %S", mrb_str_new(mrb, &c, 1)); + mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid argument specifier %c", c); break; } } @@ -1090,8 +1121,8 @@ include_module_at(mrb_state *mrb, struct RClass *c, struct RClass *ins_pos, stru MRB_API void mrb_include_module(mrb_state *mrb, struct RClass *c, struct RClass *m) { - int changed = include_module_at(mrb, c, find_origin(c), m, 1); - if (changed < 0) { + mrb_check_frozen(mrb, c); + if (include_module_at(mrb, c, find_origin(c), m, 1) < 0) { mrb_raise(mrb, E_ARGUMENT_ERROR, "cyclic include detected"); } } @@ -1102,6 +1133,7 @@ mrb_prepend_module(mrb_state *mrb, struct RClass *c, struct RClass *m) struct RClass *origin; int changed = 0; + mrb_check_frozen(mrb, c); if (!(c->flags & MRB_FL_CLASS_IS_PREPENDED)) { origin = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_ICLASS, c); origin->flags |= MRB_FL_CLASS_IS_ORIGIN | MRB_FL_CLASS_IS_INHERITED; @@ -1372,25 +1404,57 @@ mrb_method_search(mrb_state *mrb, struct RClass* c, mrb_sym mid) m = mrb_method_search_vm(mrb, &c, mid); if (MRB_METHOD_UNDEF_P(m)) { - mrb_value inspect = mrb_funcall(mrb, mrb_obj_value(c), "inspect", 0); - if (mrb_string_p(inspect) && RSTRING_LEN(inspect) > 64) { - inspect = mrb_any_to_s(mrb, mrb_obj_value(c)); - } - mrb_name_error(mrb, mid, "undefined method '%S' for class %S", - mrb_sym2str(mrb, mid), inspect); + mrb_name_error(mrb, mid, "undefined method '%n' for class %C", mid, c); } return m; } +#define ONSTACK_ALLOC_MAX 32 + +static mrb_sym +prepare_name_common(mrb_state *mrb, mrb_sym sym, const char *prefix, const char *suffix) +{ + char onstack[ONSTACK_ALLOC_MAX]; + mrb_int sym_len; + const char *sym_str = mrb_sym_name_len(mrb, sym, &sym_len); + size_t prefix_len = prefix ? strlen(prefix) : 0; + size_t suffix_len = suffix ? strlen(suffix) : 0; + size_t name_len = sym_len + prefix_len + suffix_len; + char *buf = name_len > sizeof(onstack) ? (char *)mrb_alloca(mrb, name_len) : onstack; + char *p = buf; + + if (prefix_len > 0) { + memcpy(p, prefix, prefix_len); + p += prefix_len; + } + + memcpy(p, sym_str, sym_len); + p += sym_len; + + if (suffix_len > 0) { + memcpy(p, suffix, suffix_len); + p += suffix_len; + } + + return mrb_intern(mrb, buf, name_len); +} + static mrb_value -attr_reader(mrb_state *mrb, mrb_value obj) +prepare_ivar_name(mrb_state *mrb, mrb_sym sym) { - mrb_value name = mrb_proc_cfunc_env_get(mrb, 0); - return mrb_iv_get(mrb, obj, to_sym(mrb, name)); + sym = prepare_name_common(mrb, sym, "@", NULL); + mrb_iv_name_sym_check(mrb, sym); + return mrb_symbol_value(sym); +} + +static mrb_sym +prepare_writer_name(mrb_state *mrb, mrb_sym sym) +{ + return prepare_name_common(mrb, sym, NULL, "="); } static mrb_value -mrb_mod_attr_reader(mrb_state *mrb, mrb_value mod) +mod_attr_define(mrb_state *mrb, mrb_value mod, mrb_value (*accessor)(mrb_state *, mrb_value), mrb_sym (*access_name)(mrb_state *, mrb_sym)) { struct RClass *c = mrb_class_ptr(mod); mrb_value *argv; @@ -1400,20 +1464,18 @@ mrb_mod_attr_reader(mrb_state *mrb, mrb_value mod) mrb_get_args(mrb, "*", &argv, &argc); ai = mrb_gc_arena_save(mrb); for (i=0; i<argc; i++) { - mrb_value name, str; - mrb_sym method, sym; + mrb_value name; + mrb_sym method; struct RProc *p; mrb_method_t m; method = to_sym(mrb, argv[i]); - name = mrb_sym2str(mrb, method); - str = mrb_str_new_capa(mrb, RSTRING_LEN(name)+1); - mrb_str_cat_lit(mrb, str, "@"); - mrb_str_cat_str(mrb, str, name); - sym = mrb_intern_str(mrb, str); - mrb_iv_name_sym_check(mrb, sym); - name = mrb_symbol_value(sym); - p = mrb_proc_new_cfunc_with_env(mrb, attr_reader, 1, &name); + name = prepare_ivar_name(mrb, method); + if (access_name) { + method = access_name(mrb, method); + } + + p = mrb_proc_new_cfunc_with_env(mrb, accessor, 1, &name); MRB_METHOD_FROM_PROC(m, p); mrb_define_method_raw(mrb, c, method, m); mrb_gc_arena_restore(mrb, ai); @@ -1422,6 +1484,19 @@ mrb_mod_attr_reader(mrb_state *mrb, mrb_value mod) } 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) +{ + return mod_attr_define(mrb, mod, attr_reader, NULL); +} + +static mrb_value attr_writer(mrb_state *mrb, mrb_value obj) { mrb_value name = mrb_proc_cfunc_env_get(mrb, 0); @@ -1435,42 +1510,7 @@ attr_writer(mrb_state *mrb, mrb_value obj) 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; - int ai; - - mrb_get_args(mrb, "*", &argv, &argc); - ai = mrb_gc_arena_save(mrb); - for (i=0; i<argc; i++) { - mrb_value name, str, attr; - mrb_sym method, sym; - struct RProc *p; - mrb_method_t m; - - method = to_sym(mrb, argv[i]); - - /* prepare iv name (@name) */ - name = mrb_sym2str(mrb, method); - str = mrb_str_new_capa(mrb, RSTRING_LEN(name)+1); - mrb_str_cat_lit(mrb, str, "@"); - mrb_str_cat_str(mrb, str, name); - sym = mrb_intern_str(mrb, str); - mrb_iv_name_sym_check(mrb, sym); - attr = mrb_symbol_value(sym); - - /* prepare method name (name=) */ - str = mrb_str_new_capa(mrb, RSTRING_LEN(str)); - mrb_str_cat_str(mrb, str, name); - mrb_str_cat_lit(mrb, str, "="); - method = mrb_intern_str(mrb, str); - - p = mrb_proc_new_cfunc_with_env(mrb, attr_writer, 1, &attr); - MRB_METHOD_FROM_PROC(m, p); - mrb_define_method_raw(mrb, c, method, m); - mrb_gc_arena_restore(mrb, ai); - } - return mrb_nil_value(); + return mod_attr_define(mrb, mod, attr_writer, prepare_writer_name); } static mrb_value @@ -1485,7 +1525,7 @@ mrb_instance_alloc(mrb_state *mrb, mrb_value cv) if (ttype == 0) ttype = MRB_TT_OBJECT; if (ttype <= MRB_TT_CPTR) { - mrb_raisef(mrb, E_TYPE_ERROR, "can't create instance of %S", cv); + mrb_raisef(mrb, E_TYPE_ERROR, "can't create instance of %v", cv); } o = (struct RObject*)mrb_obj_alloc(mrb, ttype, c); return mrb_obj_value(o); @@ -1503,29 +1543,20 @@ mrb_instance_alloc(mrb_state *mrb, mrb_value cv) * */ -MRB_API mrb_value +mrb_value mrb_instance_new(mrb_state *mrb, mrb_value cv) { mrb_value obj, blk; mrb_value *argv; mrb_int argc; mrb_sym init; - mrb_method_t m; - mrb_get_args(mrb, "*&", &argv, &argc, &blk); + mrb_get_args(mrb, "*!&", &argv, &argc, &blk); obj = mrb_instance_alloc(mrb, cv); init = mrb_intern_lit(mrb, "initialize"); - m = mrb_method_search(mrb, mrb_class(mrb, obj), init); - if (MRB_METHOD_CFUNC_P(m)) { - mrb_func_t f = MRB_METHOD_CFUNC(m); - if (f != mrb_bob_init) { - f(mrb, obj); - } - } - else { + if (!mrb_func_basic_p(mrb, obj, init, mrb_bob_init)) { mrb_funcall_with_block(mrb, obj, init, argc, argv, blk); } - return obj; } @@ -1569,7 +1600,10 @@ mrb_class_new_class(mrb_state *mrb, mrb_value cv) } new_class = mrb_obj_value(mrb_class_new(mrb, mrb_class_ptr(super))); mid = mrb_intern_lit(mrb, "initialize"); - if (!mrb_func_basic_p(mrb, new_class, mid, mrb_bob_init)) { + if (mrb_func_basic_p(mrb, new_class, mid, mrb_class_initialize)) { + mrb_class_initialize(mrb, new_class); + } + else { mrb_funcall_with_block(mrb, new_class, mid, n, &super, blk); } mrb_class_inherited(mrb, mrb_class_ptr(super), mrb_class_ptr(new_class)); @@ -1682,9 +1716,9 @@ mrb_class_path(mrb_state *mrb, struct RClass *c) } else if (mrb_symbol_p(path)) { /* toplevel class/module */ - return mrb_sym2str(mrb, mrb_symbol(path)); + return mrb_sym_str(mrb, mrb_symbol(path)); } - return mrb_str_dup(mrb, path); + return path; } MRB_API struct RClass* @@ -1721,7 +1755,7 @@ static void mrb_check_inheritable(mrb_state *mrb, struct RClass *super) { if (super->tt != MRB_TT_CLASS) { - mrb_raisef(mrb, E_TYPE_ERROR, "superclass must be a Class (%S given)", mrb_obj_value(super)); + mrb_raisef(mrb, E_TYPE_ERROR, "superclass must be a Class (%C given)", super); } if (super->tt == MRB_TT_SCLASS) { mrb_raise(mrb, E_TYPE_ERROR, "can't make subclass of singleton class"); @@ -1790,11 +1824,31 @@ mrb_alias_method(mrb_state *mrb, struct RClass *c, mrb_sym a, mrb_sym b) { mrb_method_t m = mrb_method_search(mrb, c, b); + if (!MRB_METHOD_CFUNC_P(m)) { + struct RProc *p = MRB_METHOD_PROC(m); + + if (MRB_PROC_ENV_P(p)) { + MRB_PROC_ENV(p)->mid = b; + } + else { + struct RClass *tc = MRB_PROC_TARGET_CLASS(p); + struct REnv *e = (struct REnv*)mrb_obj_alloc(mrb, MRB_TT_ENV, NULL); + + e->mid = b; + if (tc) { + e->c = tc; + mrb_field_write_barrier(mrb, (struct RBasic*)e, (struct RBasic*)tc); + } + p->e.env = e; + p->flags |= MRB_PROC_ENVSET; + } + } mrb_define_method_raw(mrb, c, a, m); } /*! * Defines an alias of a method. + * \param mrb the mruby state * \param klass the class which the original method belongs to * \param name1 a new name for the method * \param name2 the original name of the method @@ -1818,7 +1872,7 @@ mrb_value mrb_mod_to_s(mrb_state *mrb, mrb_value klass) { - if (mrb_type(klass) == MRB_TT_SCLASS) { + if (mrb_sclass_p(klass)) { mrb_value v = mrb_iv_get(mrb, klass, mrb_intern_lit(mrb, "__attached__")); mrb_value str = mrb_str_new_lit(mrb, "#<Class:"); @@ -1843,27 +1897,31 @@ mrb_mod_alias(mrb_state *mrb, mrb_value mod) mrb_get_args(mrb, "nn", &new_name, &old_name); mrb_alias_method(mrb, c, new_name, old_name); - return mrb_nil_value(); + return mod; +} + +static void +undef_method(mrb_state *mrb, struct RClass *c, mrb_sym a) +{ + mrb_method_t m; + + MRB_METHOD_FROM_PROC(m, NULL); + mrb_define_method_raw(mrb, c, a, m); } void mrb_undef_method_id(mrb_state *mrb, struct RClass *c, mrb_sym a) { if (!mrb_obj_respond_to(mrb, c, a)) { - mrb_name_error(mrb, a, "undefined method '%S' for class '%S'", mrb_sym2str(mrb, a), mrb_obj_value(c)); - } - else { - mrb_method_t m; - - MRB_METHOD_FROM_PROC(m, NULL); - mrb_define_method_raw(mrb, c, a, m); + mrb_name_error(mrb, a, "undefined method '%n' for class '%C'", a, c); } + undef_method(mrb, c, a); } MRB_API void mrb_undef_method(mrb_state *mrb, struct RClass *c, const char *name) { - mrb_undef_method_id(mrb, c, mrb_intern_cstr(mrb, name)); + undef_method(mrb, c, mrb_intern_cstr(mrb, name)); } MRB_API void @@ -1887,19 +1945,13 @@ mrb_mod_undef(mrb_state *mrb, mrb_value mod) return mrb_nil_value(); } -static mrb_bool -const_name_p(mrb_state *mrb, const char *name, mrb_int len) -{ - return len > 0 && ISUPPER(name[0]) && mrb_ident_p(name+1, len-1); -} - static void check_const_name_sym(mrb_state *mrb, mrb_sym id) { mrb_int len; - const char *name = mrb_sym2name_len(mrb, id, &len); - if (!const_name_p(mrb, name, len)) { - mrb_name_error(mrb, id, "wrong constant name %S", mrb_sym2str(mrb, id)); + const char *name = mrb_sym_name_len(mrb, id, &len); + if (!mrb_const_name_p(mrb, name, len)) { + mrb_name_error(mrb, id, "wrong constant name %n", id); } } @@ -1956,7 +2008,7 @@ mrb_mod_const_get(mrb_state *mrb, mrb_value mod) else { off = end + 2; if (off == len) { /* trailing "::" */ - mrb_name_error(mrb, id, "wrong constant name '%S'", path); + mrb_name_error(mrb, id, "wrong constant name '%v'", path); } } } @@ -1986,7 +2038,7 @@ mrb_mod_remove_const(mrb_state *mrb, mrb_value mod) check_const_name_sym(mrb, id); val = mrb_iv_remove(mrb, mod, id); if (mrb_undef_p(val)) { - mrb_name_error(mrb, id, "constant %S not defined", mrb_sym2str(mrb, id)); + mrb_name_error(mrb, id, "constant %n not defined", id); } return val; } @@ -1999,13 +2051,10 @@ mrb_mod_const_missing(mrb_state *mrb, mrb_value mod) mrb_get_args(mrb, "n", &sym); if (mrb_class_real(mrb_class_ptr(mod)) != mrb->object_class) { - mrb_name_error(mrb, sym, "uninitialized constant %S::%S", - mod, - mrb_sym2str(mrb, sym)); + mrb_name_error(mrb, sym, "uninitialized constant %v::%n", mod, sym); } else { - mrb_name_error(mrb, sym, "uninitialized constant %S", - mrb_sym2str(mrb, sym)); + mrb_name_error(mrb, sym, "uninitialized constant %n", sym); } /* not reached */ return mrb_nil_value(); @@ -2066,7 +2115,7 @@ mod_define_method(mrb_state *mrb, mrb_value self) /* ignored */ break; default: - mrb_raisef(mrb, E_TYPE_ERROR, "wrong argument type %S (expected Proc)", mrb_obj_value(mrb_obj_class(mrb, proc))); + mrb_raisef(mrb, E_TYPE_ERROR, "wrong argument type %T (expected Proc)", proc); break; } if (mrb_nil_p(blk)) { @@ -2099,6 +2148,14 @@ mrb_mod_eqq(mrb_state *mrb, mrb_value mod) } static mrb_value +mrb_mod_dup(mrb_state *mrb, mrb_value self) +{ + mrb_value mod = mrb_obj_clone(mrb, self); + MRB_UNSET_FROZEN_FLAG(mrb_obj_ptr(mod)); + return mod; +} + +static mrb_value mrb_mod_module_function(mrb_state *mrb, mrb_value mod) { mrb_value *argv; @@ -2146,6 +2203,40 @@ inspect_main(mrb_state *mrb, mrb_value mod) return mrb_str_new_lit(mrb, "main"); } +static const mrb_code new_iseq[] = { + OP_ENTER, 0x0, 0x10, 0x1, /* OP_ENTER 0:0:1:0:0:0:1 */ + OP_LOADSELF, 0x3, /* OP_LOADSELF R3 */ + OP_SEND, 0x3, 0x0, 0x0, /* OP_SEND R3 :allocate 0 */ + OP_MOVE, 0x0, 0x3, /* OP_MOVE R0 R3 */ + OP_MOVE, 0x4, 0x1, /* OP_MOVE R4 R1 */ + OP_MOVE, 0x5, 0x2, /* OP_MOVE R5 R2 */ + OP_SENDVB, 0x3, 0x1, /* OP_SENDVB R4 :initialize */ + OP_RETURN, 0x0 /* OP_RETURN R0 */ +}; + +static void +init_class_new(mrb_state *mrb, struct RClass *cls) +{ + struct RProc *p; + mrb_method_t m; + mrb_irep *new_irep = (mrb_irep*)mrb_malloc(mrb, sizeof(mrb_irep)); + static const mrb_irep mrb_irep_zero = { 0 }; + + *new_irep = mrb_irep_zero; + new_irep->syms = (mrb_sym*)mrb_malloc(mrb, sizeof(mrb_sym)*2); + new_irep->syms[0] = mrb_intern_lit(mrb, "allocate"); + new_irep->syms[1] = mrb_intern_lit(mrb, "initialize"); + new_irep->slen = 2; + new_irep->flags = MRB_ISEQ_NO_FREE; + new_irep->iseq = new_iseq; + new_irep->ilen = sizeof(new_iseq); + new_irep->nregs = 6; + new_irep->nlocals = 3; + p = mrb_proc_new(mrb, new_irep); + MRB_METHOD_FROM_PROC(m, p); + mrb_define_method_raw(mrb, cls, mrb_intern_lit(mrb, "new"), m); +} + void mrb_init_class(mrb_state *mrb) { @@ -2168,7 +2259,6 @@ mrb_init_class(mrb_state *mrb) /* name basic classes */ mrb_define_const(mrb, bob, "BasicObject", mrb_obj_value(bob)); - mrb_define_const(mrb, obj, "BasicObject", mrb_obj_value(bob)); mrb_define_const(mrb, obj, "Object", mrb_obj_value(obj)); mrb_define_const(mrb, obj, "Module", mrb_obj_value(mod)); mrb_define_const(mrb, obj, "Class", mrb_obj_value(cls)); @@ -2188,15 +2278,18 @@ mrb_init_class(mrb_state *mrb) mrb_define_method(mrb, bob, "==", mrb_obj_equal_m, MRB_ARGS_REQ(1)); /* 15.3.1.3.1 */ mrb_define_method(mrb, bob, "!=", mrb_obj_not_equal_m, MRB_ARGS_REQ(1)); mrb_define_method(mrb, bob, "__id__", mrb_obj_id_m, MRB_ARGS_NONE()); /* 15.3.1.3.4 */ - mrb_define_method(mrb, bob, "__send__", mrb_f_send, MRB_ARGS_ANY()); /* 15.3.1.3.5 */ - mrb_define_method(mrb, bob, "instance_eval", mrb_obj_instance_eval, MRB_ARGS_ANY()); /* 15.3.1.3.18 */ + mrb_define_method(mrb, bob, "__send__", mrb_f_send, MRB_ARGS_REQ(1)|MRB_ARGS_REST()|MRB_ARGS_BLOCK()); /* 15.3.1.3.5 */ + mrb_define_method(mrb, bob, "equal?", mrb_obj_equal_m, MRB_ARGS_REQ(1)); /* 15.3.1.3.11 */ + mrb_define_method(mrb, bob, "instance_eval", mrb_obj_instance_eval, MRB_ARGS_OPT(1)|MRB_ARGS_BLOCK()); /* 15.3.1.3.18 */ - mrb_define_class_method(mrb, cls, "new", mrb_class_new_class, MRB_ARGS_OPT(1)); + mrb_define_class_method(mrb, cls, "new", mrb_class_new_class, MRB_ARGS_OPT(1)|MRB_ARGS_BLOCK()); + mrb_define_method(mrb, cls, "allocate", mrb_instance_alloc, MRB_ARGS_NONE()); mrb_define_method(mrb, cls, "superclass", mrb_class_superclass, MRB_ARGS_NONE()); /* 15.2.3.3.4 */ - mrb_define_method(mrb, cls, "new", mrb_instance_new, MRB_ARGS_ANY()); /* 15.2.3.3.3 */ mrb_define_method(mrb, cls, "initialize", mrb_class_initialize, MRB_ARGS_OPT(1)); /* 15.2.3.3.1 */ mrb_define_method(mrb, cls, "inherited", mrb_bob_init, MRB_ARGS_REQ(1)); + init_class_new(mrb, cls); + MRB_SET_INSTANCE_TT(mod, MRB_TT_MODULE); mrb_define_method(mrb, mod, "extend_object", mrb_mod_extend_object, MRB_ARGS_REQ(1)); /* 15.2.2.4.25 */ mrb_define_method(mrb, mod, "extended", mrb_bob_init, MRB_ARGS_REQ(1)); /* 15.2.2.4.26 */ @@ -2226,7 +2319,8 @@ mrb_init_class(mrb_state *mrb) mrb_define_method(mrb, mod, "const_missing", mrb_mod_const_missing, MRB_ARGS_REQ(1)); mrb_define_method(mrb, mod, "method_defined?", mrb_mod_method_defined, MRB_ARGS_REQ(1)); /* 15.2.2.4.34 */ mrb_define_method(mrb, mod, "define_method", mod_define_method, MRB_ARGS_ARG(1,1)); - mrb_define_method(mrb, mod, "===", mrb_mod_eqq, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, mod, "===", mrb_mod_eqq, MRB_ARGS_REQ(1)); /* 15.2.2.4.7 */ + mrb_define_method(mrb, mod, "dup", mrb_mod_dup, MRB_ARGS_NONE()); mrb_undef_method(mrb, cls, "append_features"); mrb_undef_method(mrb, cls, "extend_object"); |
