summaryrefslogtreecommitdiff
path: root/class.c
diff options
context:
space:
mode:
authorknu <knu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2009-02-24 15:15:25 +0000
committerknu <knu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2009-02-24 15:15:25 +0000
commitca292099a61fd3f0f8da461515c70a17572c0712 (patch)
tree54a78e105b11532d20dc0c3b72a28b20e8dbbf6e /class.c
parentd91f52ae8b913e3aec9cc8eea3e81f1c1389af49 (diff)
* 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
Diffstat (limited to 'class.c')
-rw-r--r--class.c146
1 files changed, 68 insertions, 78 deletions
diff --git a/class.c b/class.c
index 3f87d064a1..7ba47e4e26 100644
--- a/class.c
+++ b/class.c
@@ -920,112 +920,102 @@ rb_define_attr(VALUE klass, const char *name, int read, int write)
int
rb_scan_args(int argc, const VALUE *argv, const char *fmt, ...)
{
- int i = 0, postargc, nonpostargc;
- const char *p = fmt, *q;
+ int i;
+ const char *p = fmt;
VALUE *var;
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;
- va_start(vargs, fmt);
-
- /* check the trailing mandatory argument length in advance */
- if ((q = strchr(p, '*')) != NULL && ISDIGIT(*++q)) {
- postargc = *q - '0';
- nonpostargc = argc - postargc;
- }
- else {
- postargc = 0;
- nonpostargc = argc;
+ if (ISDIGIT(*p)) {
+ n_lead = *p - '0';
+ p++;
+ if (ISDIGIT(*p)) {
+ n_opt = *p - '0';
+ p++;
+ }
}
-
if (*p == '*') {
- 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];
+ f_var = 1;
+ p++;
+ if (ISDIGIT(*p)) {
+ n_trail = *p - '0';
+ p++;
}
+ }
+ if (*p == '&') {
+ f_block = 1;
p++;
}
- else {
- goto error;
+ if (*p != '\0') {
+ rb_fatal("bad scan arg format: %s", fmt);
}
+ n_mand = n_lead + n_trail;
- /* 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;
- }
+ if (argc < n_mand)
+ goto argc_error;
+
+ va_start(vargs, fmt);
+
+ /* capture leading mandatory arguments */
+ for (i = n_lead; i-- > 0; ) {
+ var = va_arg(vargs, VALUE *);
+ if (var) *var = argv[argi];
+ argi++;
+ }
+ /* capture optional arguments */
+ for (i = n_opt; i-- > 0; ) {
+ var = va_arg(vargs, VALUE *);
+ if (argi < argc - n_trail) {
+ if (var) *var = argv[argi];
+ argi++;
+ }
+ else {
+ if (var) *var = Qnil;
}
- p++;
}
+ /* capture variable length arguments */
+ if (f_var) {
+ int n_var = argc - argi - n_trail;
- if (*p == '*') {
- rest_arg:
- /* variable length arguments (the <*rest> part) */
- var = va_arg(vargs, VALUE*);
- if (i < nonpostargc) {
- if (var) *var = rb_ary_new4(nonpostargc-i, argv+i);
- i = nonpostargc;
+ var = va_arg(vargs, VALUE *);
+ if (0 < n_var) {
+ if (var) *var = rb_ary_new4(n_var, &argv[argi]);
+ argi += n_var;
}
else {
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++;
- }
}
-
- if (*p == '&') {
- /* iterator block */
- var = va_arg(vargs, VALUE*);
+ /* capture trailing mandatory arguments */
+ for (i = n_trail; i-- > 0; ) {
+ 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()) {
*var = rb_block_proc();
}
else {
*var = Qnil;
}
- p++;
}
va_end(vargs);
- if (*p != '\0') {
- goto error;
- }
-
- if (i < argc) {
- rb_raise(rb_eArgError, "wrong number of arguments (%d for %d)", argc, i);
- }
+ if (argi < argc)
+ goto argc_error;
return argc;
- error:
- rb_fatal("bad scan arg format: %s", fmt);
- return 0;
+ argc_error:
+ if (0 < n_opt)
+ 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 ? "+" : "");
}