From fa1f5e8fd197a51d451659b718bacc3b8d37a1e5 Mon Sep 17 00:00:00 2001
From: Yusuke Endoh <mame@tsg.ne.jp>
Date: Mon, 17 Oct 2011 22:19:57 +0900
Subject: [PATCH 3/5] * implement a parser part for basic keyword arguments.

---
 compile.c |    3 +
 node.h    |    4 +
 parse.y   |  457 +++++++++++++++++++++++++++++++++++++++++++++++++++----------
 3 files changed, 392 insertions(+), 72 deletions(-)

diff --git a/compile.c b/compile.c
index 89e7059..9f1552c 100644
--- a/compile.c
+++ b/compile.c
@@ -1093,6 +1093,9 @@ iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *optargs, NODE *node_args)
 	    iseq->arg_post_len = args->post_args_num;
 	}
 
+	if (args->kw_args) {
+	    rb_notimplement();
+	}
 	if (args->opt_args) {
 	    NODE *node = args->opt_args;
 	    LABEL *label;
diff --git a/node.h b/node.h
index 873c52c..2b604f1 100644
--- a/node.h
+++ b/node.h
@@ -154,6 +154,8 @@ enum node_type {
 #define NODE_ARGS_AUX    NODE_ARGS_AUX
     NODE_OPT_ARG,
 #define NODE_OPT_ARG     NODE_OPT_ARG
+    NODE_KW_ARG,
+#define NODE_KW_ARG	 NODE_KW_ARG
     NODE_POSTARG,
 #define NODE_POSTARG     NODE_POSTARG
     NODE_ARGSCAT,
@@ -419,6 +421,7 @@ typedef struct RNode {
 #define NEW_ZSUPER() NEW_NODE(NODE_ZSUPER,0,0,0)
 #define NEW_ARGS_AUX(r,b) NEW_NODE(NODE_ARGS_AUX,r,b,0)
 #define NEW_OPT_ARG(i,v) NEW_NODE(NODE_OPT_ARG,i,v,0)
+#define NEW_KW_ARG(i,v) NEW_NODE(NODE_KW_ARG,i,v,0)
 #define NEW_POSTARG(i,v) NEW_NODE(NODE_POSTARG,i,v,0)
 #define NEW_ARGSCAT(a,b) NEW_NODE(NODE_ARGSCAT,a,b,0)
 #define NEW_ARGSPUSH(a,b) NEW_NODE(NODE_ARGSPUSH,a,b,0)
@@ -495,6 +498,7 @@ struct rb_args_info {
     ID rest_arg;
     ID block_arg;
 
+    NODE *kw_args;
     NODE *opt_args;
 };
 
diff --git a/parse.y b/parse.y
index 4a05e0f..085cf84 100644
--- a/parse.y
+++ b/parse.y
@@ -372,8 +372,8 @@ static NODE *call_bin_op_gen(struct parser_params*,NODE*,ID,NODE*);
 static NODE *call_uni_op_gen(struct parser_params*,NODE*,ID);
 #define call_uni_op(recv,id) call_uni_op_gen(parser, (recv),(id))
 
-static NODE *new_args_gen(struct parser_params*,NODE*,NODE*,ID,NODE*,ID);
-#define new_args(f,o,r,p,b) new_args_gen(parser, (f),(o),(r),(p),(b))
+static NODE *new_args_gen(struct parser_params*,NODE*,NODE*,ID,NODE*,NODE*,ID);
+#define new_args(f,o,r,p,k,b) new_args_gen(parser, (f),(o),(r),(p),(k),(b))
 
 static NODE *negate_lit(NODE*);
 static NODE *ret_args_gen(struct parser_params*,NODE*);
@@ -501,6 +501,7 @@ static VALUE ripper_dispatch2(struct parser_params*,ID,VALUE,VALUE);
 static VALUE ripper_dispatch3(struct parser_params*,ID,VALUE,VALUE,VALUE);
 static VALUE ripper_dispatch4(struct parser_params*,ID,VALUE,VALUE,VALUE,VALUE);
 static VALUE ripper_dispatch5(struct parser_params*,ID,VALUE,VALUE,VALUE,VALUE,VALUE);
+static VALUE ripper_dispatch6(struct parser_params*,ID,VALUE,VALUE,VALUE,VALUE,VALUE,VALUE);
 
 #define dispatch0(n)            ripper_dispatch0(parser, TOKEN_PASTE(ripper_id_, n))
 #define dispatch1(n,a)          ripper_dispatch1(parser, TOKEN_PASTE(ripper_id_, n), (a))
@@ -508,6 +509,7 @@ static VALUE ripper_dispatch5(struct parser_params*,ID,VALUE,VALUE,VALUE,VALUE,V
 #define dispatch3(n,a,b,c)      ripper_dispatch3(parser, TOKEN_PASTE(ripper_id_, n), (a), (b), (c))
 #define dispatch4(n,a,b,c,d)    ripper_dispatch4(parser, TOKEN_PASTE(ripper_id_, n), (a), (b), (c), (d))
 #define dispatch5(n,a,b,c,d,e)  ripper_dispatch5(parser, TOKEN_PASTE(ripper_id_, n), (a), (b), (c), (d), (e))
+#define dispatch6(n,a,b,c,d,e,f) ripper_dispatch6(parser, TOKEN_PASTE(ripper_id_, n), (a), (b), (c), (d), (e), (f))
 
 #define yyparse ripper_yyparse
 
@@ -535,8 +537,8 @@ static VALUE ripper_id2sym(ID);
 #define mlhs_add(l,a) dispatch2(mlhs_add, (l), (a))
 #define mlhs_add_star(l,a) dispatch2(mlhs_add_star, (l), (a))
 
-#define params_new(pars, opts, rest, pars2, blk) \
-        dispatch5(params, (pars), (opts), (rest), (pars2), (blk))
+#define params_new(pars, opts, rest, pars2, kws, blk) \
+        dispatch6(params, (pars), (opts), (rest), (pars2), (kws), (blk))
 
 #define blockvar_new(p,v) dispatch2(block_var, (p), (v))
 #define blockvar_add_star(l,a) dispatch2(block_var_add_star, (l), (a))
@@ -697,6 +699,7 @@ static void token_info_pop(struct parser_params*, const char *token);
 %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
+%type <node> f_kwarg f_kw f_block_kwarg f_block_kw
 %type <node> bv_decls opt_bv_decl bvar
 %type <node> lambda f_larglist lambda_body
 %type <node> brace_block cmd_brace_block do_block lhs none fitem
@@ -2900,7 +2903,7 @@ primary		: literal
 				    0),
 				node_assign($2, NEW_DVAR(id)));
 
-			    args = new_args(m, 0, id, 0, 0);
+			    args = new_args(m, 0, id, 0, 0, 0);
 			}
 			else {
 			    if (nd_type($2) == NODE_LASGN ||
@@ -2909,11 +2912,11 @@ primary		: literal
 				$2->nd_value = NEW_DVAR(id);
 				m->nd_plen = 1;
 				m->nd_next = $2;
-				args = new_args(m, 0, 0, 0, 0);
+				args = new_args(m, 0, 0, 0, 0, 0);
 			    }
 			    else {
 				m->nd_next = node_assign(NEW_MASGN(NEW_LIST($2), 0), NEW_DVAR(id));
-				args = new_args(m, 0, id, 0, 0);
+				args = new_args(m, 0, id, 0, 0, 0);
 			    }
 			}
 			scope = NEW_NODE(NODE_SCOPE, tbl, $8, args);
@@ -3317,125 +3320,237 @@ f_margs		: f_marg_list
 		    }
 		;
 
-block_param	: f_arg ',' f_block_optarg ',' f_rest_arg opt_f_block_arg
+block_param	: f_arg ',' f_block_optarg ',' f_rest_arg ',' f_block_kwarg opt_f_block_arg
 		    {
 		    /*%%%*/
-			$$ = new_args($1, $3, $5, 0, $6);
+			$$ = new_args($1, $3, $5, 0, $7, $8);
 		    /*%
-			$$ = params_new($1, $3, $5, Qnil, escape_Qundef($6));
+			$$ = params_new($1, $3, $5, Qnil, $7, escape_Qundef($8));
+		    %*/
+		    }
+		| f_arg ',' f_block_optarg ',' f_rest_arg opt_f_block_arg
+		    {
+		    /*%%%*/
+			$$ = new_args($1, $3, $5, 0, 0, $6);
+		    /*%
+			$$ = params_new($1, $3, $5, Qnil, Qnil, escape_Qundef($6));
+		    %*/
+		    }
+		| f_arg ',' f_block_optarg ',' f_rest_arg ',' f_arg ',' f_block_kwarg opt_f_block_arg
+		    {
+		    /*%%%*/
+			$$ = new_args($1, $3, $5, $7, $9, $10);
+		    /*%
+			$$ = params_new($1, $3, $5, $7, $9, escape_Qundef($10));
 		    %*/
 		    }
 		| f_arg ',' f_block_optarg ',' f_rest_arg ',' f_arg opt_f_block_arg
 		    {
 		    /*%%%*/
-			$$ = new_args($1, $3, $5, $7, $8);
+			$$ = new_args($1, $3, $5, $7, 0, $8);
+		    /*%
+			$$ = params_new($1, $3, $5, $7, Qnil, escape_Qundef($8));
+		    %*/
+		    }
+		| f_arg ',' f_block_optarg ',' f_block_kwarg opt_f_block_arg
+		    {
+		    /*%%%*/
+			$$ = new_args($1, $3, 0, 0, $5, $6);
 		    /*%
-			$$ = params_new($1, $3, $5, $7, escape_Qundef($8));
+			$$ = params_new($1, $3, Qnil, Qnil, $5, escape_Qundef($6));
 		    %*/
 		    }
 		| f_arg ',' f_block_optarg opt_f_block_arg
 		    {
 		    /*%%%*/
-			$$ = new_args($1, $3, 0, 0, $4);
+			$$ = new_args($1, $3, 0, 0, 0, $4);
+		    /*%
+			$$ = params_new($1, $3, Qnil, Qnil, Qnil, escape_Qundef($4));
+		    %*/
+		    }
+		| f_arg ',' f_block_optarg ',' f_arg ',' f_block_kwarg opt_f_block_arg
+		    {
+		    /*%%%*/
+			$$ = new_args($1, $3, 0, $5, $7, $8);
 		    /*%
-			$$ = params_new($1, $3, Qnil, Qnil, escape_Qundef($4));
+			$$ = params_new($1, $3, Qnil, $5, $7, escape_Qundef($8));
 		    %*/
 		    }
 		| f_arg ',' f_block_optarg ',' f_arg opt_f_block_arg
 		    {
 		    /*%%%*/
-			$$ = new_args($1, $3, 0, $5, $6);
+			$$ = new_args($1, $3, 0, $5, 0, $6);
 		    /*%
-			$$ = params_new($1, $3, Qnil, $5, escape_Qundef($6));
+			$$ = params_new($1, $3, Qnil, $5, Qnil, escape_Qundef($6));
+		    %*/
+		    }
+                | f_arg ',' f_rest_arg ',' f_block_kwarg opt_f_block_arg
+		    {
+		    /*%%%*/
+			$$ = new_args($1, 0, $3, 0, $5, $6);
+		    /*%
+			$$ = params_new($1, Qnil, $3, Qnil, $5, escape_Qundef($6));
 		    %*/
 		    }
                 | f_arg ',' f_rest_arg opt_f_block_arg
 		    {
 		    /*%%%*/
-			$$ = new_args($1, 0, $3, 0, $4);
+			$$ = new_args($1, 0, $3, 0, 0, $4);
 		    /*%
-			$$ = params_new($1, Qnil, $3, Qnil, escape_Qundef($4));
+			$$ = params_new($1, Qnil, $3, Qnil, Qnil, escape_Qundef($4));
 		    %*/
 		    }
 		| f_arg ','
 		    {
 		    /*%%%*/
-			$$ = new_args($1, 0, 1, 0, 0);
+			$$ = new_args($1, 0, 1, 0, 0, 0);
 		    /*%
-			$$ = params_new($1, Qnil, Qnil, Qnil, Qnil);
+			$$ = params_new($1, Qnil, Qnil, Qnil, Qnil, Qnil);
                         dispatch1(excessed_comma, $$);
 		    %*/
 		    }
+		| f_arg ',' f_rest_arg ',' f_arg ',' f_block_kwarg opt_f_block_arg
+		    {
+		    /*%%%*/
+			$$ = new_args($1, 0, $3, $5, $7, $8);
+		    /*%
+			$$ = params_new($1, Qnil, $3, $5, $7, escape_Qundef($8));
+		    %*/
+		    }
 		| f_arg ',' f_rest_arg ',' f_arg opt_f_block_arg
 		    {
 		    /*%%%*/
-			$$ = new_args($1, 0, $3, $5, $6);
+			$$ = new_args($1, 0, $3, $5, 0, $6);
 		    /*%
-			$$ = params_new($1, Qnil, $3, $5, escape_Qundef($6));
+			$$ = params_new($1, Qnil, $3, $5, Qnil, escape_Qundef($6));
+		    %*/
+		    }
+		| f_arg ',' f_block_kwarg opt_f_block_arg
+		    {
+		    /*%%%*/
+			$$ = new_args($1, 0, 0, 0, $3, $4);
+		    /*%
+			$$ = params_new($1, Qnil,Qnil, Qnil, $3, escape_Qundef($4));
 		    %*/
 		    }
 		| f_arg opt_f_block_arg
 		    {
 		    /*%%%*/
-			$$ = new_args($1, 0, 0, 0, $2);
+			$$ = new_args($1, 0, 0, 0, 0, $2);
 		    /*%
-			$$ = params_new($1, Qnil,Qnil, Qnil, escape_Qundef($2));
+			$$ = params_new($1, Qnil,Qnil, Qnil, Qnil, escape_Qundef($2));
+		    %*/
+		    }
+		| f_block_optarg ',' f_rest_arg ',' f_block_kwarg opt_f_block_arg
+		    {
+		    /*%%%*/
+			$$ = new_args(0, $1, $3, 0, $5, $6);
+		    /*%
+			$$ = params_new(Qnil, $1, $3, Qnil, $5, escape_Qundef($6));
 		    %*/
 		    }
 		| f_block_optarg ',' f_rest_arg opt_f_block_arg
 		    {
 		    /*%%%*/
-			$$ = new_args(0, $1, $3, 0, $4);
+			$$ = new_args(0, $1, $3, 0, 0, $4);
+		    /*%
+			$$ = params_new(Qnil, $1, $3, Qnil, Qnil, escape_Qundef($4));
+		    %*/
+		    }
+		| f_block_optarg ',' f_rest_arg ',' f_arg ',' f_block_kwarg opt_f_block_arg
+		    {
+		    /*%%%*/
+			$$ = new_args(0, $1, $3, $5, $7, $8);
 		    /*%
-			$$ = params_new(Qnil, $1, $3, Qnil, escape_Qundef($4));
+			$$ = params_new(Qnil, $1, $3, $5, $7, escape_Qundef($8));
 		    %*/
 		    }
 		| f_block_optarg ',' f_rest_arg ',' f_arg opt_f_block_arg
 		    {
 		    /*%%%*/
-			$$ = new_args(0, $1, $3, $5, $6);
+			$$ = new_args(0, $1, $3, $5, 0, $6);
 		    /*%
-			$$ = params_new(Qnil, $1, $3, $5, escape_Qundef($6));
+			$$ = params_new(Qnil, $1, $3, $5, Qnil, escape_Qundef($6));
+		    %*/
+		    }
+		| f_block_optarg ',' f_block_kwarg opt_f_block_arg
+		    {
+		    /*%%%*/
+			$$ = new_args(0, $1, 0, 0, $3, $4);
+		    /*%
+			$$ = params_new(Qnil, $1, Qnil, Qnil, $3, escape_Qundef($4));
 		    %*/
 		    }
 		| f_block_optarg opt_f_block_arg
 		    {
 		    /*%%%*/
-			$$ = new_args(0, $1, 0, 0, $2);
+			$$ = new_args(0, $1, 0, 0, 0, $2);
 		    /*%
-			$$ = params_new(Qnil, $1, Qnil, Qnil,escape_Qundef($2));
+			$$ = params_new(Qnil, $1, Qnil, Qnil, Qnil, escape_Qundef($2));
+		    %*/
+		    }
+		| f_block_optarg ',' f_arg ',' f_block_kwarg opt_f_block_arg
+		    {
+		    /*%%%*/
+			$$ = new_args(0, $1, 0, $3, $5, $6);
+		    /*%
+			$$ = params_new(Qnil, $1, Qnil, $3, $5, escape_Qundef($6));
 		    %*/
 		    }
 		| f_block_optarg ',' f_arg opt_f_block_arg
 		    {
 		    /*%%%*/
-			$$ = new_args(0, $1, 0, $3, $4);
+			$$ = new_args(0, $1, 0, $3, 0, $4);
 		    /*%
-			$$ = params_new(Qnil, $1, Qnil, $3, escape_Qundef($4));
+			$$ = params_new(Qnil, $1, Qnil, $3, Qnil, escape_Qundef($4));
+		    %*/
+		    }
+		| f_rest_arg ',' f_block_kwarg opt_f_block_arg
+		    {
+		    /*%%%*/
+			$$ = new_args(0, 0, $1, 0, $3, $4);
+		    /*%
+			$$ = params_new(Qnil, Qnil, $1, Qnil, $3, escape_Qundef($4));
 		    %*/
 		    }
 		| f_rest_arg opt_f_block_arg
 		    {
 		    /*%%%*/
-			$$ = new_args(0, 0, $1, 0, $2);
+			$$ = new_args(0, 0, $1, 0, 0, $2);
 		    /*%
-			$$ = params_new(Qnil, Qnil, $1, Qnil, escape_Qundef($2));
+			$$ = params_new(Qnil, Qnil, $1, Qnil, Qnil, escape_Qundef($2));
+		    %*/
+		    }
+		| f_rest_arg ',' f_arg ',' f_block_kwarg opt_f_block_arg
+		    {
+		    /*%%%*/
+			$$ = new_args(0, 0, $1, $3, $5, $6);
+		    /*%
+			$$ = params_new(Qnil, Qnil, $1, $3, $5, escape_Qundef($6));
 		    %*/
 		    }
 		| f_rest_arg ',' f_arg opt_f_block_arg
 		    {
 		    /*%%%*/
-			$$ = new_args(0, 0, $1, $3, $4);
+			$$ = new_args(0, 0, $1, $3, 0, $4);
+		    /*%
+			$$ = params_new(Qnil, Qnil, $1, $3, Qnil, escape_Qundef($4));
+		    %*/
+		    }
+		| f_block_kwarg opt_f_block_arg
+		    {
+		    /*%%%*/
+			$$ = new_args(0, 0, 0, 0, $1, $2);
 		    /*%
-			$$ = params_new(Qnil, Qnil, $1, $3, escape_Qundef($4));
+			$$ = params_new(Qnil, Qnil, Qnil, Qnil, $1, escape_Qundef($2));
 		    %*/
 		    }
 		| f_block_arg
 		    {
 		    /*%%%*/
-			$$ = new_args(0, 0, 0, 0, $1);
+			$$ = new_args(0, 0, 0, 0, 0, $1);
 		    /*%
-			$$ = params_new(Qnil, Qnil, Qnil, Qnil, $1);
+			$$ = params_new(Qnil, Qnil, Qnil, Qnil, Qnil, $1);
 		    %*/
 		    }
 		;
@@ -3452,7 +3567,7 @@ block_param_def	: '|' opt_bv_decl '|'
 		    /*%%%*/
 			$$ = 0;
 		    /*%
-			$$ = blockvar_new(params_new(Qnil,Qnil,Qnil,Qnil,Qnil),
+			$$ = blockvar_new(params_new(Qnil,Qnil,Qnil,Qnil,Qnil,Qnil),
                                           escape_Qundef($2));
 		    %*/
 		    }
@@ -3461,7 +3576,7 @@ block_param_def	: '|' opt_bv_decl '|'
 		    /*%%%*/
 			$$ = 0;
 		    /*%
-			$$ = blockvar_new(params_new(Qnil,Qnil,Qnil,Qnil,Qnil),
+			$$ = blockvar_new(params_new(Qnil,Qnil,Qnil,Qnil,Qnil,Qnil),
                                           Qnil);
 		    %*/
 		    }
@@ -4376,124 +4491,236 @@ f_arglist	: '(' f_args rparen
 		    }
 		;
 
-f_args		: f_arg ',' f_optarg ',' f_rest_arg opt_f_block_arg
+f_args		: f_arg ',' f_optarg ',' f_rest_arg ',' f_kwarg opt_f_block_arg
+		    {
+		    /*%%%*/
+			$$ = new_args($1, $3, $5, 0, $7, $8);
+		    /*%
+			$$ = params_new($1, $3, $5, Qnil, $7, escape_Qundef($8));
+		    %*/
+		    }
+		| f_arg ',' f_optarg ',' f_rest_arg opt_f_block_arg
+		    {
+		    /*%%%*/
+			$$ = new_args($1, $3, $5, 0, 0, $6);
+		    /*%
+			$$ = params_new($1, $3, $5, Qnil, Qnil, escape_Qundef($6));
+		    %*/
+		    }
+		| f_arg ',' f_optarg ',' f_rest_arg ',' f_arg ',' f_kwarg opt_f_block_arg
 		    {
 		    /*%%%*/
-			$$ = new_args($1, $3, $5, 0, $6);
+			$$ = new_args($1, $3, $5, $7, $9, $10);
 		    /*%
-			$$ = params_new($1, $3, $5, Qnil, escape_Qundef($6));
+			$$ = params_new($1, $3, $5, $7, $9, escape_Qundef($10));
 		    %*/
 		    }
 		| f_arg ',' f_optarg ',' f_rest_arg ',' f_arg opt_f_block_arg
 		    {
 		    /*%%%*/
-			$$ = new_args($1, $3, $5, $7, $8);
+			$$ = new_args($1, $3, $5, $7, 0, $8);
 		    /*%
-			$$ = params_new($1, $3, $5, $7, escape_Qundef($8));
+			$$ = params_new($1, $3, $5, $7, Qnil, escape_Qundef($8));
+		    %*/
+		    }
+		| f_arg ',' f_optarg ',' f_kwarg opt_f_block_arg
+		    {
+		    /*%%%*/
+			$$ = new_args($1, $3, 0, 0, $5, $6);
+		    /*%
+			$$ = params_new($1, $3, Qnil, Qnil, $5, escape_Qundef($6));
 		    %*/
 		    }
 		| f_arg ',' f_optarg opt_f_block_arg
 		    {
 		    /*%%%*/
-			$$ = new_args($1, $3, 0, 0, $4);
+			$$ = new_args($1, $3, 0, 0, 0, $4);
 		    /*%
-			$$ = params_new($1, $3, Qnil, Qnil, escape_Qundef($4));
+			$$ = params_new($1, $3, Qnil, Qnil, Qnil, escape_Qundef($4));
+		    %*/
+		    }
+		| f_arg ',' f_optarg ',' f_arg ',' f_kwarg opt_f_block_arg
+		    {
+		    /*%%%*/
+			$$ = new_args($1, $3, 0, $5, $7, $8);
+		    /*%
+			$$ = params_new($1, $3, Qnil, $5, $7, escape_Qundef($8));
 		    %*/
 		    }
 		| f_arg ',' f_optarg ',' f_arg opt_f_block_arg
 		    {
 		    /*%%%*/
-			$$ = new_args($1, $3, 0, $5, $6);
+			$$ = new_args($1, $3, 0, $5, 0, $6);
+		    /*%
+			$$ = params_new($1, $3, Qnil, $5, Qnil, escape_Qundef($6));
+		    %*/
+		    }
+		| f_arg ',' f_rest_arg ',' f_kwarg opt_f_block_arg
+		    {
+		    /*%%%*/
+			$$ = new_args($1, 0, $3, 0, $5, $6);
 		    /*%
-			$$ = params_new($1, $3, Qnil, $5, escape_Qundef($6));
+			$$ = params_new($1, Qnil, $3, Qnil, $5, escape_Qundef($6));
 		    %*/
 		    }
 		| f_arg ',' f_rest_arg opt_f_block_arg
 		    {
 		    /*%%%*/
-			$$ = new_args($1, 0, $3, 0, $4);
+			$$ = new_args($1, 0, $3, 0, 0, $4);
 		    /*%
-			$$ = params_new($1, Qnil, $3, Qnil, escape_Qundef($4));
+			$$ = params_new($1, Qnil, $3, Qnil, Qnil, escape_Qundef($4));
+		    %*/
+		    }
+		| f_arg ',' f_rest_arg ',' f_arg ',' f_kwarg opt_f_block_arg
+		    {
+		    /*%%%*/
+			$$ = new_args($1, 0, $3, $5, $7, $8);
+		    /*%
+			$$ = params_new($1, Qnil, $3, $5, $7, escape_Qundef($8));
 		    %*/
 		    }
 		| f_arg ',' f_rest_arg ',' f_arg opt_f_block_arg
 		    {
 		    /*%%%*/
-			$$ = new_args($1, 0, $3, $5, $6);
+			$$ = new_args($1, 0, $3, $5, 0, $6);
+		    /*%
+			$$ = params_new($1, Qnil, $3, $5, Qnil, escape_Qundef($6));
+		    %*/
+		    }
+		| f_arg ',' f_kwarg opt_f_block_arg
+		    {
+		    /*%%%*/
+			$$ = new_args($1, 0, 0, 0, $3, $4);
 		    /*%
-			$$ = params_new($1, Qnil, $3, $5, escape_Qundef($6));
+			$$ = params_new($1, Qnil, Qnil, Qnil, $3, escape_Qundef($4));
 		    %*/
 		    }
 		| f_arg opt_f_block_arg
 		    {
 		    /*%%%*/
-			$$ = new_args($1, 0, 0, 0, $2);
+			$$ = new_args($1, 0, 0, 0, 0, $2);
 		    /*%
-			$$ = params_new($1, Qnil, Qnil, Qnil,escape_Qundef($2));
+			$$ = params_new($1, Qnil, Qnil, Qnil, Qnil, escape_Qundef($2));
+		    %*/
+		    }
+		| f_optarg ',' f_rest_arg ',' f_kwarg opt_f_block_arg
+		    {
+		    /*%%%*/
+			$$ = new_args(0, $1, $3, 0, $5, $6);
+		    /*%
+			$$ = params_new(Qnil, $1, $3, Qnil, $5, escape_Qundef($6));
 		    %*/
 		    }
 		| f_optarg ',' f_rest_arg opt_f_block_arg
 		    {
 		    /*%%%*/
-			$$ = new_args(0, $1, $3, 0, $4);
+			$$ = new_args(0, $1, $3, 0, 0, $4);
+		    /*%
+			$$ = params_new(Qnil, $1, $3, Qnil, Qnil, escape_Qundef($4));
+		    %*/
+		    }
+		| f_optarg ',' f_rest_arg ',' f_arg ',' f_kwarg opt_f_block_arg
+		    {
+		    /*%%%*/
+			$$ = new_args(0, $1, $3, $5, $7, $8);
 		    /*%
-			$$ = params_new(Qnil, $1, $3, Qnil, escape_Qundef($4));
+			$$ = params_new(Qnil, $1, $3, $5, $7, escape_Qundef($8));
 		    %*/
 		    }
 		| f_optarg ',' f_rest_arg ',' f_arg opt_f_block_arg
 		    {
 		    /*%%%*/
-			$$ = new_args(0, $1, $3, $5, $6);
+			$$ = new_args(0, $1, $3, $5, 0, $6);
 		    /*%
-			$$ = params_new(Qnil, $1, $3, $5, escape_Qundef($6));
+			$$ = params_new(Qnil, $1, $3, $5, Qnil, escape_Qundef($6));
+		    %*/
+		    }
+		| f_optarg ',' f_kwarg opt_f_block_arg
+		    {
+		    /*%%%*/
+			$$ = new_args(0, $1, 0, 0, $3, $4);
+		    /*%
+			$$ = params_new(Qnil, $1, Qnil, Qnil, $3, escape_Qundef($4));
 		    %*/
 		    }
 		| f_optarg opt_f_block_arg
 		    {
 		    /*%%%*/
-			$$ = new_args(0, $1, 0, 0, $2);
+			$$ = new_args(0, $1, 0, 0, 0, $2);
 		    /*%
-			$$ = params_new(Qnil, $1, Qnil, Qnil,escape_Qundef($2));
+			$$ = params_new(Qnil, $1, Qnil, Qnil, Qnil, escape_Qundef($2));
+		    %*/
+		    }
+		| f_optarg ',' f_arg ',' f_kwarg opt_f_block_arg
+		    {
+		    /*%%%*/
+			$$ = new_args(0, $1, 0, $3, $5, $6);
+		    /*%
+			$$ = params_new(Qnil, $1, Qnil, $3, $5, escape_Qundef($6));
 		    %*/
 		    }
 		| f_optarg ',' f_arg opt_f_block_arg
 		    {
 		    /*%%%*/
-			$$ = new_args(0, $1, 0, $3, $4);
+			$$ = new_args(0, $1, 0, $3, 0, $4);
 		    /*%
-			$$ = params_new(Qnil, $1, Qnil, $3, escape_Qundef($4));
+			$$ = params_new(Qnil, $1, Qnil, $3, Qnil, escape_Qundef($4));
+		    %*/
+		    }
+		| f_rest_arg ',' f_kwarg opt_f_block_arg
+		    {
+		    /*%%%*/
+			$$ = new_args(0, 0, $1, 0, $3, $4);
+		    /*%
+			$$ = params_new(Qnil, Qnil, $1, Qnil, $3, escape_Qundef($4));
 		    %*/
 		    }
 		| f_rest_arg opt_f_block_arg
 		    {
 		    /*%%%*/
-			$$ = new_args(0, 0, $1, 0, $2);
+			$$ = new_args(0, 0, $1, 0, 0, $2);
 		    /*%
-			$$ = params_new(Qnil, Qnil, $1, Qnil,escape_Qundef($2));
+			$$ = params_new(Qnil, Qnil, $1, Qnil, Qnil, escape_Qundef($2));
+		    %*/
+		    }
+		| f_rest_arg ',' f_arg ',' f_kwarg opt_f_block_arg
+		    {
+		    /*%%%*/
+			$$ = new_args(0, 0, $1, $3, $5, $6);
+		    /*%
+			$$ = params_new(Qnil, Qnil, $1, $3, $5, escape_Qundef($6));
 		    %*/
 		    }
 		| f_rest_arg ',' f_arg opt_f_block_arg
 		    {
 		    /*%%%*/
-			$$ = new_args(0, 0, $1, $3, $4);
+			$$ = new_args(0, 0, $1, $3, 0, $4);
+		    /*%
+			$$ = params_new(Qnil, Qnil, $1, $3,  Qnil, escape_Qundef($4));
+		    %*/
+		    }
+		| f_kwarg opt_f_block_arg
+		    {
+		    /*%%%*/
+			$$ = new_args(0, 0, 0, 0, $1, $2);
 		    /*%
-			$$ = params_new(Qnil, Qnil, $1, $3, escape_Qundef($4));
+			$$ = params_new(Qnil, Qnil, Qnil, Qnil, $1, escape_Qundef($2));
 		    %*/
 		    }
 		| f_block_arg
 		    {
 		    /*%%%*/
-			$$ = new_args(0, 0, 0, 0, $1);
+			$$ = new_args(0, 0, 0, 0, 0, $1);
 		    /*%
-			$$ = params_new(Qnil, Qnil, Qnil, Qnil, $1);
+			$$ = params_new(Qnil, Qnil, Qnil, Qnil, Qnil, $1);
 		    %*/
 		    }
 		| /* none */
 		    {
 		    /*%%%*/
-			$$ = new_args(0, 0, 0, 0, 0);
+			$$ = new_args(0, 0, 0, 0, 0, 0);
 		    /*%
-			$$ = params_new(Qnil, Qnil, Qnil, Qnil, Qnil);
+			$$ = params_new(Qnil, Qnil, Qnil, Qnil, Qnil, Qnil);
 		    %*/
 		    }
 		;
@@ -4592,6 +4819,79 @@ f_arg		: f_arg_item
 		    }
 		;
 
+f_kw		: tLABEL arg_value
+		    {
+			arg_var(formal_argument(get_id($1)));
+			$$ = assignable($1, $2);
+		    /*%%%*/
+			$$ = NEW_KW_ARG(0, $$);
+		    /*%
+			$$ = rb_assoc_new($$, $2);
+		    %*/
+		    }
+		;
+
+f_block_kw	: tLABEL primary_value
+		    {
+			arg_var(formal_argument(get_id($1)));
+			$$ = assignable($1, $2);
+		    /*%%%*/
+			$$ = NEW_KW_ARG(0, $$);
+		    /*%
+			$$ = rb_assoc_new($$, $2);
+		    %*/
+		    }
+		;
+
+f_block_kwarg	: f_block_kw
+		    {
+		    /*%%%*/
+			$$ = $1;
+		    /*%
+			$$ = rb_ary_new3(1, $1);
+		    %*/
+		    }
+		| f_block_kwarg ',' f_block_kw
+		    {
+		    /*%%%*/
+			NODE *kws = $1;
+
+			while (kws->nd_next) {
+			    kws = kws->nd_next;
+			}
+			kws->nd_next = $3;
+			$$ = $1;
+		    /*%
+			$$ = rb_ary_push($1, $3);
+		    %*/
+		    }
+		;
+
+
+f_kwarg		: f_kw
+		    {
+		    /*%%%*/
+			$$ = $1;
+		    /*%
+			$$ = rb_ary_new3(1, $1);
+		    %*/
+		    }
+		| f_kwarg ',' f_kw
+		    {
+		    /*%%%*/
+			NODE *kws = $1;
+
+			while (kws->nd_next) {
+			    kws = kws->nd_next;
+			}
+			kws->nd_next = $3;
+			$$ = $1;
+		    /*%
+			$$ = rb_ary_push($1, $3);
+		    %*/
+		    }
+		;
+
 f_opt		: tIDENTIFIER '=' arg_value
 		    {
 			arg_var(formal_argument(get_id($1)));
@@ -9066,7 +9366,7 @@ arg_blk_pass(NODE *node1, NODE *node2)
 }
 
 static NODE*
-new_args_gen(struct parser_params *parser, NODE *m, NODE *o, ID r, NODE *p, ID b)
+new_args_gen(struct parser_params *parser, NODE *m, NODE *o, ID r, NODE *p, NODE *k, ID b)
 {
     int saved_line = ruby_sourceline;
     struct rb_args_info *args;
@@ -9083,6 +9383,7 @@ new_args_gen(struct parser_params *parser, NODE *m, NODE *o, ID r, NODE *p, ID b
     args->rest_arg       = r;
     args->block_arg      = b;
 
+    args->kw_args        = k;
     args->opt_args       = o;
 
     ruby_sourceline = saved_line;
@@ -10601,6 +10902,18 @@ ripper_dispatch5(struct parser_params *parser, ID mid, VALUE a, VALUE b, VALUE c
     return rb_funcall(parser->value, mid, 5, a, b, c, d, e);
 }
 
+static VALUE
+ripper_dispatch6(struct parser_params *parser, ID mid, VALUE a, VALUE b, VALUE c, VALUE d, VALUE e, VALUE f)
+{
+    validate(a);
+    validate(b);
+    validate(c);
+    validate(d);
+    validate(e);
+    validate(f);
+    return rb_funcall(parser->value, mid, 6, a, b, c, d, e, f);
+}
+
 static const struct kw_assoc {
     ID id;
     const char *name;
-- 
1.7.5.4

