* class.c (rb_scan_args): Revamp rb_scan_args() to compute the

number of required and optional arguments precisely to prepare
  for a more informative error message.


git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@22601 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
knu 2009-02-24 15:15:25 +00:00
parent d91f52ae8b
commit ca292099a6
2 changed files with 77 additions and 81 deletions

View File

@ -1,3 +1,9 @@
Wed Feb 25 00:05:13 2009 Akinori MUSHA <knu@iDaemons.org>
* class.c (rb_scan_args): Revamp rb_scan_args() to compute the
number of required and optional arguments precisely to prepare
for a more informative error message.
Tue Feb 24 23:58:52 2009 Akinori MUSHA <knu@iDaemons.org> Tue Feb 24 23:58:52 2009 Akinori MUSHA <knu@iDaemons.org>
* array.c (rb_ary_index, rb_ary_rindex): Emit a warning that a * array.c (rb_ary_index, rb_ary_rindex): Emit a warning that a

152
class.c
View File

@ -920,112 +920,102 @@ rb_define_attr(VALUE klass, const char *name, int read, int write)
int int
rb_scan_args(int argc, const VALUE *argv, const char *fmt, ...) rb_scan_args(int argc, const VALUE *argv, const char *fmt, ...)
{ {
int i = 0, postargc, nonpostargc; int i;
const char *p = fmt, *q; const char *p = fmt;
VALUE *var; VALUE *var;
va_list vargs; va_list vargs;
int f_var = 0, f_block = 0;
int n_lead = 0, n_opt = 0, n_trail = 0, n_mand;
int argi = 0;
if (ISDIGIT(*p)) {
n_lead = *p - '0';
p++;
if (ISDIGIT(*p)) {
n_opt = *p - '0';
p++;
}
}
if (*p == '*') {
f_var = 1;
p++;
if (ISDIGIT(*p)) {
n_trail = *p - '0';
p++;
}
}
if (*p == '&') {
f_block = 1;
p++;
}
if (*p != '\0') {
rb_fatal("bad scan arg format: %s", fmt);
}
n_mand = n_lead + n_trail;
if (argc < n_mand)
goto argc_error;
va_start(vargs, fmt); va_start(vargs, fmt);
/* check the trailing mandatory argument length in advance */ /* capture leading mandatory arguments */
if ((q = strchr(p, '*')) != NULL && ISDIGIT(*++q)) { for (i = n_lead; i-- > 0; ) {
postargc = *q - '0'; var = va_arg(vargs, VALUE *);
nonpostargc = argc - postargc; if (var) *var = argv[argi];
argi++;
} }
else { /* capture optional arguments */
postargc = 0; for (i = n_opt; i-- > 0; ) {
nonpostargc = argc; var = va_arg(vargs, VALUE *);
} if (argi < argc - n_trail) {
if (var) *var = argv[argi];
if (*p == '*') { argi++;
if (nonpostargc < 0)
rb_raise(rb_eArgError, "wrong number of arguments (%d for %d)",
argc, postargc);
goto rest_arg;
}
else if (ISDIGIT(*p)) {
/* leading mandatory arguments */
int n = *p - '0';
if (nonpostargc < n)
rb_raise(rb_eArgError, "wrong number of arguments (%d for %d)",
argc, n + postargc);
for (; n-- > 0; i++) {
var = va_arg(vargs, VALUE*);
if (var) *var = argv[i];
} }
p++; else {
} if (var) *var = Qnil;
else {
goto error;
}
/* optional arguments (typically with default values) */
if (ISDIGIT(*p)) {
int n = *p - '0';
for (; n-- > 0; ) {
var = va_arg(vargs, VALUE*);
if (i < nonpostargc) {
if (var) *var = argv[i];
i++;
}
else {
if (var) *var = Qnil;
}
} }
p++;
} }
/* capture variable length arguments */
if (f_var) {
int n_var = argc - argi - n_trail;
if (*p == '*') { var = va_arg(vargs, VALUE *);
rest_arg: if (0 < n_var) {
/* variable length arguments (the <*rest> part) */ if (var) *var = rb_ary_new4(n_var, &argv[argi]);
var = va_arg(vargs, VALUE*); argi += n_var;
if (i < nonpostargc) {
if (var) *var = rb_ary_new4(nonpostargc-i, argv+i);
i = nonpostargc;
} }
else { else {
if (var) *var = rb_ary_new(); if (var) *var = rb_ary_new();
} }
p++;
if (0 < postargc) {
/* trailing mandatory arguments */
int n = postargc;
for (; n-- > 0; i++) {
var = va_arg(vargs, VALUE*);
if (var) *var = argv[i];
}
p++;
}
} }
/* capture trailing mandatory arguments */
if (*p == '&') { for (i = n_trail; i-- > 0; ) {
/* iterator block */ var = va_arg(vargs, VALUE *);
var = va_arg(vargs, VALUE*); if (var) *var = argv[argi];
argi++;
}
/* capture iterator block */
if (f_block) {
var = va_arg(vargs, VALUE *);
if (rb_block_given_p()) { if (rb_block_given_p()) {
*var = rb_block_proc(); *var = rb_block_proc();
} }
else { else {
*var = Qnil; *var = Qnil;
} }
p++;
} }
va_end(vargs); va_end(vargs);
if (*p != '\0') { if (argi < argc)
goto error; goto argc_error;
}
if (i < argc) {
rb_raise(rb_eArgError, "wrong number of arguments (%d for %d)", argc, i);
}
return argc; return argc;
error: argc_error:
rb_fatal("bad scan arg format: %s", fmt); if (0 < n_opt)
return 0; rb_raise(rb_eArgError, "wrong number of arguments (%d for %d..%d%s)",
argc, n_mand, n_mand + n_opt, f_var ? "+" : "");
else
rb_raise(rb_eArgError, "wrong number of arguments (%d for %d%s)",
argc, n_mand, f_var ? "+" : "");
} }