diff options
| author | Yukihiro Matsumoto <[email protected]> | 2012-05-24 01:09:36 +0900 |
|---|---|---|
| committer | Yukihiro Matsumoto <[email protected]> | 2012-05-24 01:09:36 +0900 |
| commit | ad9e841c5359efdd37a132767e03ad7a2d5ae72e (patch) | |
| tree | 8e60edf2dce29e86d8b47d0b2e8dc8a2a2329ded /src/class.c | |
| parent | 4f012f578f22cca67af8c633845464abc79913f4 (diff) | |
| download | mruby-ad9e841c5359efdd37a132767e03ad7a2d5ae72e.tar.gz mruby-ad9e841c5359efdd37a132767e03ad7a2d5ae72e.zip | |
made mrb_get_args() better (optinal args, type checks); close #173 #176
Diffstat (limited to 'src/class.c')
| -rw-r--r-- | src/class.c | 249 |
1 files changed, 169 insertions, 80 deletions
diff --git a/src/class.c b/src/class.c index 05b02a894..c6dfdd568 100644 --- a/src/class.c +++ b/src/class.c @@ -328,15 +328,67 @@ mrb_define_method_vm(mrb_state *mrb, struct RClass *c, mrb_sym name, mrb_value b kh_value(h, k) = mrb_proc_ptr(body); } +static mrb_value +check_type(mrb_state *mrb, mrb_value val, enum mrb_vtype t, const char *c, const char *m) +{ + mrb_value tmp; + + tmp = mrb_check_convert_type(mrb, val, t, c, m); + if (mrb_nil_p(tmp)) { + mrb_raise(mrb, E_TYPE_ERROR, "expected %s", c); + } + return tmp; +} + +static mrb_value +to_str(mrb_state *mrb, mrb_value val) +{ + return check_type(mrb, val, MRB_TT_STRING, "String", "to_str"); +} + +static mrb_value +to_ary(mrb_state *mrb, mrb_value val) +{ + return check_type(mrb, val, MRB_TT_ARRAY, "Array", "to_ary"); +} + +static mrb_value +to_hash(mrb_state *mrb, mrb_value val) +{ + return check_type(mrb, val, MRB_TT_HASH, "Hash", "to_hash"); +} + +/* + retrieve arguments from mrb_state. + + mrb_get_args(mrb, format, ...) + + returns number of arguments parsed. + + fortmat specifiers: + + o: Object [mrb_value] + S: String [mrb_value] + A: Array [mrb_value] + H: Hash [mrb_value] + s: String [char*,int] + z: String [char*] + a: Array [mrb_value*,int] + f: Float [mrb_float] + i: Integer [mrb_int] + &: Block [mrb_value] + *: rest argument [mrb_value*,int] + |: optional + */ int mrb_get_args(mrb_state *mrb, const char *format, ...) { char c; - int i=0; + int i = 0; mrb_value *sp = mrb->stack + 1; va_list ap; int argc = mrb->ci->argc; - int *argcp; + int opt = 0; va_start(ap, format); if (argc < 0) { @@ -346,39 +398,92 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) sp = a->buf; } while ((c = *format++)) { + if (argc < i) { + if (opt) continue; + mrb_raise(mrb, E_ARGUMENT_ERROR, "wrong number of arguments"); + } switch (c) { case 'o': { mrb_value *p; + p = va_arg(ap, mrb_value*); *p = *sp; i++; sp++; } break; - case 'i': + case 'S': { - mrb_int *p; + mrb_value *p; - p = va_arg(ap, mrb_int*); - switch (sp->tt) { - case MRB_TT_FIXNUM: - *p = mrb_fixnum(*sp); - break; - case MRB_TT_FLOAT: - *p = (mrb_int)mrb_float(*sp); - break; - case MRB_TT_FALSE: - *p = 0; - break; - default: - { - mrb_value tmp; + p = va_arg(ap, mrb_value*); + *p = to_str(mrb, *sp); + i++; sp++; + } + break; + case 'A': + { + mrb_value *p; - tmp = mrb_convert_type(mrb, *sp, MRB_TT_FIXNUM, "Integer", "to_int"); - *p = mrb_fixnum(tmp); - } - break; - } + p = va_arg(ap, mrb_value*); + *p = to_ary(mrb, *sp); + i++; sp++; + } + break; + case 'H': + { + mrb_value *p; + + p = va_arg(ap, mrb_value*); + *p = to_hash(mrb, *sp); + i++; sp++; + } + break; + case 's': + { + mrb_value ss; + struct RString *s; + char **ps = 0; + int *pl = 0; + + ss = to_str(mrb, *sp); + s = mrb_str_ptr(ss); + ps = va_arg(ap, char**); + *ps = s->buf; + pl = va_arg(ap, int*); + *pl = s->len; + i++; sp++; + } + break; + case 'z': + { + mrb_value ss; + struct RString *s; + char **ps; + + ss = to_str(mrb, *sp); + s = mrb_str_ptr(ss); + if (strlen(s->buf) != s->len) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "String contains NUL"); + } + ps = va_arg(ap, char**); + *ps = s->buf; + i++; sp++; + } + break; + case 'a': + { + mrb_value aa; + struct RArray *a; + mrb_value **pb; + int *pl; + + aa = to_ary(mrb, *sp); + a = mrb_ary_ptr(aa); + pb = va_arg(ap, mrb_value**); + *pb = a->buf; + pl = va_arg(ap, int*); + *pl = a->len; i++; sp++; } break; @@ -409,53 +514,34 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) i++; sp++; } break; - case 's': + case 'i': { - char **ps = 0; - size_t *pl = 0; - struct RString *s; + mrb_int *p; - if (argc > i) { - s = mrb_str_ptr(*sp); - ps = va_arg(ap, char**); - *ps = s->buf; - pl = va_arg(ap, size_t*); - *pl = s->len; + p = va_arg(ap, mrb_int*); + switch (sp->tt) { + case MRB_TT_FIXNUM: + *p = mrb_fixnum(*sp); + break; + case MRB_TT_FLOAT: + *p = (mrb_int)mrb_float(*sp); + break; + case MRB_TT_FALSE: + *p = 0; + break; + default: + { + mrb_value tmp; + + tmp = mrb_convert_type(mrb, *sp, MRB_TT_FIXNUM, "Integer", "to_int"); + *p = mrb_fixnum(tmp); + } + break; } i++; sp++; } break; - case 'a': - { - mrb_value *var; - var = va_arg(ap, mrb_value*); - if (argc > i) { - if (var) { - memcpy(var, sp, sizeof(mrb_value)*(argc-i)); - } - //i = mrb->argc; - } - else { - if (var) *var = mrb_ary_new(mrb); - } - argcp = va_arg(ap, int*); - *argcp = argc-i; - goto last_var; - } - break; - case 'b': - { - struct RProc **p; - mrb_value *bp = mrb->stack + 1; - p = va_arg(ap, struct RProc**); - if (mrb->ci->argc > 0) { - bp += mrb->ci->argc; - } - if (mrb_nil_p(*bp)) *p = 0; - else *p = mrb_proc_ptr(*bp); - } - break; case '&': { mrb_value *p, *bp = mrb->stack + 1; @@ -467,30 +553,34 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) *p = *bp; } break; + case '|': + opt = 1; + break; case '*': { mrb_value **var; + int *pl; + var = va_arg(ap, mrb_value**); - argcp = va_arg(ap, int*); + pl = va_arg(ap, int*); if (argc > i) { - *argcp = argc-i; - if (*argcp > 0) { - if (var) { - *var = sp; - } - i += *argcp; + *pl = argc-i; + if (*pl > 0) { + *var = sp; + i = argc; } } else { - *argcp = 0; + *pl = 0; *var = NULL; } - goto last_var; } break; } } -last_var: + if (!*format && argc > i) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "wrong number of arguments"); + } va_end(ap); return 0; } @@ -679,17 +769,17 @@ mrb_value mrb_class_new_instance_m(mrb_state *mrb, mrb_value klass) { mrb_value *argv; - struct RProc *b; + mrb_value blk; struct RClass *k = mrb_class_ptr(klass); struct RClass *c; int argc; mrb_value obj; - mrb_get_args(mrb, "b*", &b, &argv, &argc); + mrb_get_args(mrb, "*&", &argv, &argc, &blk); c = (struct RClass*)mrb_obj_alloc(mrb, k->tt, k); c->super = k; obj = mrb_obj_value(c); - mrb_funcall_with_block(mrb, obj, "initialize", argc, argv, b); + mrb_funcall_with_block(mrb, obj, "initialize", argc, argv, blk); return obj; } @@ -698,18 +788,17 @@ mrb_value mrb_instance_new(mrb_state *mrb, mrb_value cv) { struct RClass *c = mrb_class_ptr(cv); - struct RProc *b; struct RObject *o; enum mrb_vtype ttype = MRB_INSTANCE_TT(c); - mrb_value obj; + mrb_value obj, blk; mrb_value *argv; int argc; if (ttype == 0) ttype = MRB_TT_OBJECT; o = (struct RObject*)mrb_obj_alloc(mrb, ttype, c); obj = mrb_obj_value(o); - mrb_get_args(mrb, "b*", &b, &argv, &argc); - mrb_funcall_with_block(mrb, obj, "initialize", argc, argv, b); + mrb_get_args(mrb, "*&", &argv, &argc, &blk); + mrb_funcall_with_block(mrb, obj, "initialize", argc, argv, blk); return obj; } |
