From f5ca95ee10189e91c39c63f4bedbfa6fa75ef763 Mon Sep 17 00:00:00 2001 From: knu Date: Mon, 16 Feb 2009 08:04:56 +0000 Subject: [PATCH] * class.c (rb_scan_args), README.EXT, README.EXT.ja: Add support for specifying the number of the trailing mandatory arguments. Update the documents accordingly. [ruby-dev:37995] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@22339 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ChangeLog | 6 +++++ README.EXT | 3 ++- README.EXT.ja | 3 ++- class.c | 65 ++++++++++++++++++++++++++++++++++++++------------- 4 files changed, 59 insertions(+), 18 deletions(-) diff --git a/ChangeLog b/ChangeLog index 787aa708fd..b25c9aeb06 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +Mon Feb 16 17:04:14 2009 Akinori MUSHA + + * class.c (rb_scan_args), README.EXT, README.EXT.ja: Add support + for specifying the number of the trailing mandatory arguments. + Update the documents accordingly. [ruby-dev:37995] + Mon Feb 16 16:46:14 2009 Nobuyoshi Nakada * debug.c (set_debug_option): added rtc_error option. diff --git a/README.EXT b/README.EXT index 2d02708255..6364ab7a80 100644 --- a/README.EXT +++ b/README.EXT @@ -687,13 +687,14 @@ scan-arg-spec := param-arg-spec [block-arg-spec] param-arg-spec := pre-arg-spec [post-arg-spec] / post-arg-spec pre-arg-spec := num-of-leading-mandatory-args [num-of-optional-args] -post-arg-spec := sym-for-variable-length-args +post-arg-spec := sym-for-variable-length-args [num-of-trailing-mandatory-args] block-arg-spec := sym-for-block-arg num-of-leading-mandatory-args := DIGIT ; -- the number of the leading mandatory arguments num-of-optional-args := DIGIT ; -- the number of the following optional arguments sym-for-variable-length-args := "*" ; -- indicates that the following variable length ; arguments are captured as a Ruby array +num-of-trailing-mandatory-args := DIGIT ; -- the number of the trailing mandatory arguments sym-for-block-arg := "&" ; -- indicates that the iterator block should be ; captured if given -- diff --git a/README.EXT.ja b/README.EXT.ja index d7a688f721..feecc26e2b 100644 --- a/README.EXT.ja +++ b/README.EXT.ja @@ -775,13 +775,14 @@ scan-arg-spec := param-arg-spec [block-arg-spec] param-arg-spec := pre-arg-spec [post-arg-spec] / post-arg-spec pre-arg-spec := num-of-leading-mandatory-args [num-of-optional-args] -post-arg-spec := sym-for-variable-length-args +post-arg-spec := sym-for-variable-length-args [num-of-trailing-mandatory-args] block-arg-spec := sym-for-block-arg num-of-leading-mandatory-args := DIGIT ; -- 先頭に置かれる省略不可能な引数の数 num-of-optional-args := DIGIT ; -- 続いて置かれる省略可能な引数の数 sym-for-variable-length-args := "*" ; -- 続いて置かれる可変長引数をRubyの配列で ; 取得するための指定 +num-of-trailing-mandatory-args := DIGIT ; -- 終端に置かれる省略不可能な引数の数 sym-for-block-arg := "&" ; -- イテレータブロックを取得するための指定 -- diff --git a/class.c b/class.c index 89becccb54..38e4ef6fe5 100644 --- a/class.c +++ b/class.c @@ -920,20 +920,37 @@ 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 n, i = 0; - const char *p = fmt; + int i = 0, postargc, nonpostargc; + const char *p = fmt, *q; VALUE *var; va_list vargs; va_start(vargs, fmt); - if (*p == '*') goto rest_arg; + /* 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 = *p - '0'; - if (n > argc) - rb_raise(rb_eArgError, "wrong number of arguments (%d for %d)", argc, n); - for (i=0; i 0; i++) { var = va_arg(vargs, VALUE*); if (var) *var = argv[i]; } @@ -943,12 +960,15 @@ rb_scan_args(int argc, const VALUE *argv, const char *fmt, ...) goto error; } + /* optional arguments (typically with default values) */ if (ISDIGIT(*p)) { - n = i + *p - '0'; - for (; i 0; ) { var = va_arg(vargs, VALUE*); - if (argc > i) { + if (i < nonpostargc) { if (var) *var = argv[i]; + i++; } else { if (var) *var = Qnil; @@ -957,20 +977,33 @@ rb_scan_args(int argc, const VALUE *argv, const char *fmt, ...) p++; } - if(*p == '*') { + if (*p == '*') { rest_arg: + /* variable length arguments (the <*rest> part) */ var = va_arg(vargs, VALUE*); - if (argc > i) { - if (var) *var = rb_ary_new4(argc-i, argv+i); - i = argc; + if (i < nonpostargc) { + if (var) *var = rb_ary_new4(nonpostargc-i, argv+i); + i = nonpostargc; } 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*); if (rb_block_given_p()) { *var = rb_block_proc(); @@ -986,7 +1019,7 @@ rb_scan_args(int argc, const VALUE *argv, const char *fmt, ...) goto error; } - if (argc > i) { + if (i < argc) { rb_raise(rb_eArgError, "wrong number of arguments (%d for %d)", argc, i); }