From: Eric Mahurin Date: 2008-05-25T07:27:29+09:00 Subject: [PATCH] block args w/ defaults (was Re: resolving lambda | ambiguity) ------=_Part_4183_7502088.1211668067317 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit Content-Disposition: inline On Sat, May 24, 2008 at 4:06 PM, Eric Mahurin wrote: > On Fri, May 23, 2008 at 7:18 AM, ts wrote: > >> Eric Mahurin wrote: >> > Is there any reason this idea couldn't be applied to head? >> >> Try it on your personal version. >> >> Guy Decoux > > > Here is a patch for handling optional args for blocks using this simple > idea - use a "primary_value" instead of "arg_value" for the default values. > I simply did some cutting and pasting for the argument definitions for "def" > and changed "arg_value" to "primary_value". It worked on the first try! > Spent more time writing tests (included) than adding the new functionality. > > Matz, any chance this could be integrated for a trial period at least? It > shouldn't cause any compatibility issues. > For some reason, gmail attached my patch with base64 encoding. A simple cut-n-paste of the patch is below. Also here would be a reasonable ChangeLog entry: * parse.y (block_param) : added alternatives for allowing arguments with defaults. These are identical to what is in f_args except f_block_optarg is used instead of f_optarg. f_block_optarg is the same as f_optarg except primary_value is used instead of arg_value. * sample/test.rb (assignment) : tested these new alternatives with defaults for arguments. Index: sample/test.rb =================================================================== --- sample/test.rb (revision 16568) +++ sample/test.rb (working copy) @@ -296,6 +296,64 @@ test_ok(f.call([42,55]) == [[42,55]]) test_ok(f.call(42,55) == [42,55]) +f = lambda { |a, b=42, *c| [a,b,c] } +test_ok(f.call(1 ) == [1,42,[ ]] ) +test_ok(f.call(1,43 ) == [1,43,[ ]] ) +test_ok(f.call(1,43,44) == [1,43,[44]] ) + +f = lambda { |a, b=(a|16), *c, &block| [a,b,c,block&&block[]] } +test_ok(f.call(8 ) == [8,24,[ ],nil] ) +test_ok(f.call(8,43 ) == [8,43,[ ],nil] ) +test_ok(f.call(8,43,44) == [8,43,[44],nil] ) +test_ok(f.call(8 ){45} == [8,24,[ ],45 ] ) +test_ok(f.call(8,43 ){45} == [8,43,[ ],45 ] ) +test_ok(f.call(8,43,44){45} == [8,43,[44],45 ] ) + +f = lambda { |a, b=42, *c, d| [a,b,c,d] } +test_ok(f.call(1 ,99) == [1,42,[ ],99] ) +test_ok(f.call(1,43 ,99) == [1,43,[ ],99] ) +test_ok(f.call(1,43,44,99) == [1,43,[44],99] ) + +f = lambda { |a, b=(a|16), &block| [a,b,block&&block[]] } +test_ok(f.call(8 ) == [8,24,nil] ) +test_ok(f.call(8,43) == [8,43,nil] ) +test_ok(f.call(8,43) == [8,43,nil] ) +test_ok(f.call(8 ){45} == [8,24,45 ] ) +test_ok(f.call(8,43){45} == [8,43,45 ] ) +test_ok(f.call(8,43){45} == [8,43,45 ] ) + +f = lambda { |a, b=42, d| [a,b,d] } +test_ok(f.call(1 ,99) == [1,42,99] ) +test_ok(f.call(1,43,99) == [1,43,99] ) +test_ok(f.call(1,43,99) == [1,43,99] ) + +f = lambda { |b=42, *c, &block| [b,c,block&&block[]] } +test_ok(f.call( ) == [42,[ ],nil] ) +test_ok(f.call(43 ) == [43,[ ],nil] ) +test_ok(f.call(43,44) == [43,[44],nil] ) +test_ok(f.call( ){45} == [42,[ ],45 ] ) +test_ok(f.call(43 ){45} == [43,[ ],45 ] ) +test_ok(f.call(43,44){45} == [43,[44],45 ] ) + +f = lambda { |b=42, *c, d| [b,c,d] } +test_ok(f.call( 99) == [42,[ ],99] ) +test_ok(f.call(43 ,99) == [43,[ ],99] ) +test_ok(f.call(43,44,99) == [43,[44],99] ) + +f = lambda { |b=42, &block| [b,block&&block[]] } +test_ok(f.call( ) == [42,nil] ) +test_ok(f.call(43) == [43,nil] ) +test_ok(f.call(43) == [43,nil] ) +test_ok(f.call( ){45} == [42,45 ] ) +test_ok(f.call(43){45} == [43,45 ] ) +test_ok(f.call(43){45} == [43,45 ] ) + +f = lambda { |b=42, d| [b,d] } +test_ok(f.call( 99) == [42,99] ) +test_ok(f.call(43,99) == [43,99] ) +test_ok(f.call(43,99) == [43,99] ) + + a,=*[1] test_ok(a == 1) a,=*[[1]] Index: parse.y =================================================================== --- parse.y (revision 16568) +++ parse.y (working copy) @@ -666,6 +666,7 @@ %type open_args paren_args opt_paren_args %type command_args aref_args opt_block_arg block_arg var_ref var_lhs %type mrhs superclass block_call block_command +%type f_block_optarg f_block_opt %type f_arglist f_args f_arg f_arg_item f_optarg f_marg f_marg_list f_margs %type assoc_list assocs assoc undef_list backref string_dvar for_var %type block_param opt_block_param block_param_def f_opt @@ -3169,9 +3170,41 @@ } ; -block_param : f_arg ',' f_rest_arg opt_f_block_arg +block_param : f_arg ',' f_block_optarg ',' f_rest_arg opt_f_block_arg { /*%%%*/ + $$ = new_args($1, $3, $5, 0, $6); + /*% + $$ = params_new($1, $3, $5, Qnil, escape_Qundef($6)); + %*/ + } + | f_arg ',' f_block_optarg ',' f_rest_arg ',' f_arg opt_f_block_arg + { + /*%%%*/ + $$ = new_args($1, $3, $5, $7, $8); + /*% + $$ = params_new($1, $3, $5, $7, escape_Qundef($8)); + %*/ + } + | f_arg ',' f_block_optarg opt_f_block_arg + { + /*%%%*/ + $$ = new_args($1, $3, 0, 0, $4); + /*% + $$ = params_new($1, $3, Qnil, Qnil, escape_Qundef($4)); + %*/ + } + | f_arg ',' f_block_optarg ',' f_arg opt_f_block_arg + { + /*%%%*/ + $$ = new_args($1, $3, 0, $5, $6); + /*% + $$ = params_new($1, $3, Qnil, $5, escape_Qundef($6)); + %*/ + } + | f_arg ',' f_rest_arg opt_f_block_arg + { + /*%%%*/ $$ = new_args($1, 0, $3, 0, $4); /*% $$ = params_new($1, Qnil, $3, Qnil, escape_Qundef($4)); @@ -3202,6 +3235,38 @@ $$ = params_new($1, Qnil,Qnil, Qnil, escape_Qundef($2)); %*/ } + | f_block_optarg ',' f_rest_arg opt_f_block_arg + { + /*%%%*/ + $$ = new_args(0, $1, $3, 0, $4); + /*% + $$ = params_new(Qnil, $1, $3, Qnil, escape_Qundef($4)); + %*/ + } + | f_block_optarg ',' f_rest_arg ',' f_arg opt_f_block_arg + { + /*%%%*/ + $$ = new_args(0, $1, $3, $5, $6); + /*% + $$ = params_new(Qnil, $1, $3, $5, escape_Qundef($6)); + %*/ + } + | f_block_optarg opt_f_block_arg + { + /*%%%*/ + $$ = new_args(0, $1, 0, 0, $2); + /*% + $$ = params_new(Qnil, $1, Qnil, Qnil,escape_Qundef($2)); + %*/ + } + | f_block_optarg ',' f_arg opt_f_block_arg + { + /*%%%*/ + $$ = new_args(0, $1, 0, $3, $4); + /*% + $$ = params_new(Qnil, $1, Qnil, $3, escape_Qundef($4)); + %*/ + } | f_rest_arg opt_f_block_arg { /*%%%*/ @@ -4302,6 +4367,44 @@ } ; +f_block_opt : tIDENTIFIER '=' primary_value + { + /*%%%*/ + if (!is_local_id($1)) + yyerror("formal argument must be local variable"); + shadowing_lvar($1); + arg_var($1); + $$ = NEW_OPT_ARG(0, assignable($1, $3)); + /*% + $$ = rb_assoc_new($1, $3); + %*/ + } + ; + +f_block_optarg : f_block_opt + { + /*%%%*/ + $$ = $1; + /*% + $$ = rb_ary_new3(1, $1); + %*/ + } + | f_block_optarg ',' f_block_opt + { + /*%%%*/ + NODE *opts = $1; + + while (opts->nd_next) { + opts = opts->nd_next; + } + opts->nd_next = $3; + $$ = $1; + /*% + $$ = rb_ary_push($1, $3); + %*/ + } + ; + f_optarg : f_opt { /*%%%*/ ------=_Part_4183_7502088.1211668067317 Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit Content-Disposition: inline On Sat, May 24, 2008 at 4:06 PM, Eric Mahurin <eric.mahurin@gmail.com> wrote:
On Fri, May 23, 2008 at 7:18 AM, ts <decoux@moulon.inra.fr> wrote:
Eric Mahurin wrote:
> Is there any reason this idea couldn't be applied to head?

 Try it on your personal version.

Guy Decoux

Here is a patch for handling optional args for blocks using this simple idea - use a "primary_value" instead of "arg_value" for the default values.  I simply did some cutting and pasting for the argument definitions for "def" and changed "arg_value" to "primary_value".  It worked on the first try!  Spent more time writing tests (included) than adding the new functionality.

Matz, any chance this could be integrated for a trial period at least?  It shouldn't cause any compatibility issues.

For some reason, gmail attached my patch with base64 encoding.  A simple cut-n-paste of the patch is below.  Also here would be a reasonable ChangeLog entry:

* parse.y (block_param) : added alternatives for allowing arguments with defaults.  These are identical to what is in f_args except f_block_optarg is used instead of f_optarg.  f_block_optarg is the same as f_optarg except primary_value is used instead of arg_value.
* sample/test.rb (assignment) : tested these new alternatives with defaults for arguments.


Index: sample/test.rb
===================================================================
--- sample/test.rb    (revision 16568)
+++ sample/test.rb    (working copy)
@@ -296,6 +296,64 @@
 test_ok(f.call([42,55]) == [[42,55]])
 test_ok(f.call(42,55) == [42,55])
 
+f = lambda { |a, b=42, *c| [a,b,c] }
+test_ok(f.call(1      ) == [1,42,[  ]] )
+test_ok(f.call(1,43   ) == [1,43,[  ]] )
+test_ok(f.call(1,43,44) == [1,43,[44]] )
+
+f = lambda { |a, b=(a|16), *c, &block| [a,b,c,block&&block[]] }
+test_ok(f.call(8      )     == [8,24,[  ],nil] )
+test_ok(f.call(8,43   )     == [8,43,[  ],nil] )
+test_ok(f.call(8,43,44)     == [8,43,[44],nil] )
+test_ok(f.call(8      ){45} == [8,24,[  ],45 ] )
+test_ok(f.call(8,43   ){45} == [8,43,[  ],45 ] )
+test_ok(f.call(8,43,44){45} == [8,43,[44],45 ] )
+
+f = lambda { |a, b=42, *c, d| [a,b,c,d] }
+test_ok(f.call(1      ,99) == [1,42,[  ],99] )
+test_ok(f.call(1,43   ,99) == [1,43,[  ],99] )
+test_ok(f.call(1,43,44,99) == [1,43,[44],99] )
+
+f = lambda { |a, b=(a|16), &block| [a,b,block&&block[]] }
+test_ok(f.call(8   )     == [8,24,nil] )
+test_ok(f.call(8,43)     == [8,43,nil] )
+test_ok(f.call(8,43)     == [8,43,nil] )
+test_ok(f.call(8   ){45} == [8,24,45 ] )
+test_ok(f.call(8,43){45} == [8,43,45 ] )
+test_ok(f.call(8,43){45} == [8,43,45 ] )
+
+f = lambda { |a, b=42, d| [a,b,d] }
+test_ok(f.call(1   ,99) == [1,42,99] )
+test_ok(f.call(1,43,99) == [1,43,99] )
+test_ok(f.call(1,43,99) == [1,43,99] )
+
+f = lambda { |b=42, *c, &block| [b,c,block&&block[]] }
+test_ok(f.call(     )     == [42,[  ],nil] )
+test_ok(f.call(43   )     == [43,[  ],nil] )
+test_ok(f.call(43,44)     == [43,[44],nil] )
+test_ok(f.call(     ){45} == [42,[  ],45 ] )
+test_ok(f.call(43   ){45} == [43,[  ],45 ] )
+test_ok(f.call(43,44){45} == [43,[44],45 ] )
+
+f = lambda { |b=42, *c, d| [b,c,d] }
+test_ok(f.call(      99) == [42,[  ],99] )
+test_ok(f.call(43   ,99) == [43,[  ],99] )
+test_ok(f.call(43,44,99) == [43,[44],99] )
+
+f = lambda { |b=42, &block| [b,block&&block[]] }
+test_ok(f.call(  )     == [42,nil] )
+test_ok(f.call(43)     == [43,nil] )
+test_ok(f.call(43)     == [43,nil] )
+test_ok(f.call(  ){45} == [42,45 ] )
+test_ok(f.call(43){45} == [43,45 ] )
+test_ok(f.call(43){45} == [43,45 ] )
+
+f = lambda { |b=42, d| [b,d] }
+test_ok(f.call(   99) == [42,99] )
+test_ok(f.call(43,99) == [43,99] )
+test_ok(f.call(43,99) == [43,99] )
+
+
 a,=*[1]
 test_ok(a == 1)
 a,=*[[1]]
Index: parse.y
===================================================================
--- parse.y    (revision 16568)
+++ parse.y    (working copy)
@@ -666,6 +666,7 @@
 %type <node> open_args paren_args opt_paren_args
 %type <node> command_args aref_args opt_block_arg block_arg var_ref var_lhs
 %type <node> mrhs superclass block_call block_command
+%type <node> f_block_optarg f_block_opt
 %type <node> f_arglist f_args f_arg f_arg_item f_optarg f_marg f_marg_list f_margs
 %type <node> assoc_list assocs assoc undef_list backref string_dvar for_var
 %type <node> block_param opt_block_param block_param_def f_opt
@@ -3169,9 +3170,41 @@
             }
         ;
 
-block_param    : f_arg ',' f_rest_arg opt_f_block_arg
+block_param    : f_arg ',' f_block_optarg ',' f_rest_arg opt_f_block_arg
             {
             /*%%%*/
+            $$ = new_args($1, $3, $5, 0, $6);
+            /*%
+            $$ = params_new($1, $3, $5, Qnil, escape_Qundef($6));
+            %*/
+            }
+        | f_arg ',' f_block_optarg ',' f_rest_arg ',' f_arg opt_f_block_arg
+            {
+            /*%%%*/
+            $$ = new_args($1, $3, $5, $7, $8);
+            /*%
+            $$ = params_new($1, $3, $5, $7, escape_Qundef($8));
+            %*/
+            }
+        | f_arg ',' f_block_optarg opt_f_block_arg
+            {
+            /*%%%*/
+            $$ = new_args($1, $3, 0, 0, $4);
+            /*%
+            $$ = params_new($1, $3, Qnil, Qnil, escape_Qundef($4));
+            %*/
+            }
+        | f_arg ',' f_block_optarg ',' f_arg opt_f_block_arg
+            {
+            /*%%%*/
+            $$ = new_args($1, $3, 0, $5, $6);
+            /*%
+            $$ = params_new($1, $3, Qnil, $5, escape_Qundef($6));
+            %*/
+            }
+                | f_arg ',' f_rest_arg opt_f_block_arg
+            {
+            /*%%%*/
             $$ = new_args($1, 0, $3, 0, $4);
             /*%
             $$ = params_new($1, Qnil, $3, Qnil, escape_Qundef($4));
@@ -3202,6 +3235,38 @@
             $$ = params_new($1, Qnil,Qnil, Qnil, escape_Qundef($2));
             %*/
             }
+        | f_block_optarg ',' f_rest_arg opt_f_block_arg
+            {
+            /*%%%*/
+            $$ = new_args(0, $1, $3, 0, $4);
+            /*%
+            $$ = params_new(Qnil, $1, $3, Qnil, escape_Qundef($4));
+            %*/
+            }
+        | f_block_optarg ',' f_rest_arg ',' f_arg opt_f_block_arg
+            {
+            /*%%%*/
+            $$ = new_args(0, $1, $3, $5, $6);
+            /*%
+            $$ = params_new(Qnil, $1, $3, $5, escape_Qundef($6));
+            %*/
+            }
+        | f_block_optarg opt_f_block_arg
+            {
+            /*%%%*/
+            $$ = new_args(0, $1, 0, 0, $2);
+            /*%
+            $$ = params_new(Qnil, $1, Qnil, Qnil,escape_Qundef($2));
+            %*/
+            }
+        | f_block_optarg ',' f_arg opt_f_block_arg
+            {
+            /*%%%*/
+            $$ = new_args(0, $1, 0, $3, $4);
+            /*%
+            $$ = params_new(Qnil, $1, Qnil, $3, escape_Qundef($4));
+            %*/
+            }
         | f_rest_arg opt_f_block_arg
             {
             /*%%%*/
@@ -4302,6 +4367,44 @@
             }
         ;
 
+f_block_opt    : tIDENTIFIER '=' primary_value
+            {
+            /*%%%*/
+            if (!is_local_id($1))
+                yyerror("formal argument must be local variable");
+            shadowing_lvar($1);
+            arg_var($1);
+            $$ = NEW_OPT_ARG(0, assignable($1, $3));
+            /*%
+            $$ = rb_assoc_new($1, $3);
+            %*/
+            }
+        ;
+
+f_block_optarg    : f_block_opt
+            {
+            /*%%%*/
+            $$ = $1;
+            /*%
+            $$ = rb_ary_new3(1, $1);
+            %*/
+            }
+        | f_block_optarg ',' f_block_opt
+            {
+            /*%%%*/
+            NODE *opts = $1;
+
+            while (opts->nd_next) {
+                opts = opts->nd_next;
+            }
+            opts->nd_next = $3;
+            $$ = $1;
+            /*%
+            $$ = rb_ary_push($1, $3);
+            %*/
+            }
+        ;
+
 f_optarg    : f_opt
             {
             /*%%%*/
------=_Part_4183_7502088.1211668067317--