diff --git a/ChangeLog b/ChangeLog index dbd749b1d9..3ed9d9d478 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +Tue Mar 13 22:00:14 2012 Nobuyoshi Nakada + + * compile.c (iseq_set_arguments): keyword rest arg without keyword args. + + * node.c (dump_node): dump kw_rest_arg too. + + * parse.y (block_param, f_arg): more kwrest patterns. + [ruby-core:42455][Bug #5989] + + * parse.y (new_args_gen): no extra kw_rest_arg if no keyword rest arg. + Tue Mar 13 15:17:03 2012 Nobuyoshi Nakada * parse.y (block_param, f_args): add rules for the case arguments diff --git a/compile.c b/compile.c index d4b7d2c79b..31b41f0d65 100644 --- a/compile.c +++ b/compile.c @@ -1166,6 +1166,12 @@ iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *optargs, NODE *node_args) } ADD_INSN(optargs, nd_line(args->kw_args), pop); } + else if (args->kw_rest_arg) { + iseq->arg_keyword = get_dyna_var_idx_at_raw(iseq, args->kw_rest_arg->nd_vid); + COMPILE(optargs, "kwarg", args->kw_rest_arg); + iseq->arg_keyword_check = (args->kw_rest_arg->nd_vid & ID_SCOPE_MASK) == ID_JUNK; + ADD_INSN(optargs, nd_line(args->kw_rest_arg), pop); + } else { iseq->arg_keyword = -1; } @@ -4992,17 +4998,17 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped) ADD_INSN1(ret, nd_line(node), putobject, ID2SYM(id)); ADD_SEND(ret, nd_line(node), ID2SYM(rb_intern("delete")), INT2FIX(1)); switch (nd_type(node->nd_body)) { - case NODE_LASGN: - idx = iseq->local_iseq->local_size - get_local_var_idx(iseq, id); - ADD_INSN1(ret, nd_line(node), setlocal, INT2FIX(idx)); - break; - case NODE_DASGN: - case NODE_DASGN_CURR: - idx = get_dyna_var_idx(iseq, id, &lv, &ls); - ADD_INSN2(ret, nd_line(node), setdynamic, INT2FIX(ls - idx), INT2FIX(lv)); - break; - default: - rb_bug("iseq_compile_each (NODE_KW_ARG): unknown node: %s", ruby_node_name(nd_type(node->nd_body))); + case NODE_LASGN: + idx = iseq->local_iseq->local_size - get_local_var_idx(iseq, id); + ADD_INSN1(ret, nd_line(node), setlocal, INT2FIX(idx)); + break; + case NODE_DASGN: + case NODE_DASGN_CURR: + idx = get_dyna_var_idx(iseq, id, &lv, &ls); + ADD_INSN2(ret, nd_line(node), setdynamic, INT2FIX(ls - idx), INT2FIX(lv)); + break; + default: + rb_bug("iseq_compile_each (NODE_KW_ARG): unknown node: %s", ruby_node_name(nd_type(node->nd_body))); } ADD_INSNL(ret, nd_line(node), jump, end_label); ADD_LABEL(ret, default_label); diff --git a/node.c b/node.c index d4c2d9b02c..b3936dad07 100644 --- a/node.c +++ b/node.c @@ -860,6 +860,7 @@ dump_node(VALUE buf, VALUE indent, int comment, NODE *node) F_NODE(nd_ainfo->opt_args, "optional arguments"); LAST_NODE; F_NODE(nd_ainfo->kw_args, "keyword arguments"); + F_NODE(nd_ainfo->kw_rest_arg, "keyword rest argument"); break; case NODE_SCOPE: diff --git a/parse.y b/parse.y index 579da3a391..37fb8f9e87 100644 --- a/parse.y +++ b/parse.y @@ -373,8 +373,10 @@ 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*,NODE*,ID,ID); -#define new_args(f,o,r,p,k,kr,b) new_args_gen(parser, (f),(o),(r),(p),(k),(kr),(b)) +static NODE *new_args_gen(struct parser_params*,NODE*,NODE*,ID,NODE*,NODE*); +#define new_args(f,o,r,p,t) new_args_gen(parser, (f),(o),(r),(p),(t)) +static NODE *new_args_tail_gen(struct parser_params*,NODE*,ID,ID); +#define new_args_tail(k,kr,b) new_args_tail_gen(parser, (k),(kr),(b)) static NODE *negate_lit(NODE*); static NODE *ret_args_gen(struct parser_params*,NODE*); @@ -541,6 +543,19 @@ static VALUE ripper_id2sym(ID); #define params_new(pars, opts, rest, pars2, kws, kwrest, blk) \ dispatch7(params, (pars), (opts), (rest), (pars2), (kws), (kwrest), (blk)) +static inline VALUE +new_args(VALUE f, VALUE o, VALUE r, VALUE p, NODE *t) +{ + VALUE k = t->u1.value, kr = t->u2.value, b = t->u3.value; + return params_new(f, o, r, p, k, kr, escape_Qundef(b)); +} + +static inline NODE * +new_args_tail(VALUE k, VALUE kr, VALUE b) +{ + return rb_node_newnode(NODE_MEMO, k, kr, b); +} + #define blockvar_new(p,v) dispatch2(block_var, (p), (v)) #define blockvar_add_star(l,a) dispatch2(block_var_add_star, (l), (a)) #define blockvar_add_block(l,a) dispatch2(block_var_add_block, (l), (a)) @@ -556,8 +571,10 @@ static VALUE ripper_id2sym(ID); #endif /* RIPPER */ #ifndef RIPPER +# define Qnone 0 # define ifndef_ripper(x) (x) #else +# define Qnone Qnil # define ifndef_ripper(x) #endif @@ -693,7 +710,7 @@ static void token_info_pop(struct parser_params*, const char *token); %type expr_value arg_value primary_value %type if_tail opt_else case_body cases opt_rescue exc_list exc_var opt_ensure %type args call_args opt_call_args -%type paren_args opt_paren_args +%type paren_args opt_paren_args args_tail opt_args_tail block_args_tail opt_block_args_tail %type command_args aref_args opt_block_arg block_arg var_ref var_lhs %type command_asgn mrhs superclass block_call block_command %type f_block_optarg f_block_opt @@ -2918,7 +2935,7 @@ primary : literal 0), node_assign($2, NEW_DVAR(id))); - args = new_args(m, 0, id, 0, 0, 0, 0); + args = new_args(m, 0, id, 0, new_args_tail(0, 0, 0)); } else { if (nd_type($2) == NODE_LASGN || @@ -2927,11 +2944,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, 0, 0); + args = new_args(m, 0, 0, 0, new_args_tail(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, 0, 0); + args = new_args(m, 0, id, 0, new_args_tail(0, 0, 0)); } } scope = NEW_NODE(NODE_SCOPE, tbl, $8, args); @@ -3335,359 +3352,98 @@ f_margs : f_marg_list } ; -block_param : f_arg ',' f_block_optarg ',' f_rest_arg ',' f_block_kwarg f_kwrest opt_f_block_arg + +block_args_tail : f_block_kwarg ',' f_kwrest opt_f_block_arg { - /*%%%*/ - $$ = new_args($1, $3, $5, 0, $7, $8, $9); - /*% - $$ = params_new($1, $3, $5, Qnil, $7, $8, escape_Qundef($9)); - %*/ - } - | f_arg ',' f_block_optarg ',' f_rest_arg ',' f_block_kwarg opt_f_block_arg - { - /*%%%*/ - $$ = new_args($1, $3, $5, 0, $7, 0, $8); - /*% - $$ = params_new($1, $3, $5, Qnil, $7, Qnil, escape_Qundef($8)); - %*/ - } - | f_arg ',' f_block_optarg ',' f_rest_arg opt_f_block_arg - { - /*%%%*/ - $$ = new_args($1, $3, $5, 0, 0, 0, $6); - /*% - $$ = params_new($1, $3, $5, Qnil, Qnil, Qnil, escape_Qundef($6)); - %*/ - } - | f_arg ',' f_block_optarg ',' f_rest_arg ',' f_arg ',' f_block_kwarg f_kwrest opt_f_block_arg - { - /*%%%*/ - $$ = new_args($1, $3, $5, $7, $9, $10, $11); - /*% - $$ = params_new($1, $3, $5, $7, $9, $10, escape_Qundef($11)); - %*/ - } - | f_arg ',' f_block_optarg ',' f_rest_arg ',' f_arg ',' f_block_kwarg opt_f_block_arg - { - /*%%%*/ - $$ = new_args($1, $3, $5, $7, $9, 0, $10); - /*% - $$ = params_new($1, $3, $5, $7, $9, Qnil, escape_Qundef($10)); - %*/ - } - | f_arg ',' f_block_optarg ',' f_rest_arg ',' f_arg opt_f_block_arg - { - /*%%%*/ - $$ = new_args($1, $3, $5, $7, 0, 0, $8); - /*% - $$ = params_new($1, $3, $5, $7, Qnil, Qnil, escape_Qundef($8)); - %*/ - } - | f_arg ',' f_block_optarg ',' f_block_kwarg f_kwrest opt_f_block_arg - { - /*%%%*/ - $$ = new_args($1, $3, 0, 0, $5, $6, $7); - /*% - $$ = params_new($1, $3, Qnil, Qnil, $5, $6, escape_Qundef($7)); - %*/ - } - | f_arg ',' f_block_optarg ',' f_block_kwarg opt_f_block_arg - { - /*%%%*/ - $$ = new_args($1, $3, 0, 0, $5, 0, $6); - /*% - $$ = params_new($1, $3, Qnil, Qnil, $5, Qnil, escape_Qundef($6)); - %*/ - } - | f_arg ',' f_block_optarg opt_f_block_arg - { - /*%%%*/ - $$ = new_args($1, $3, 0, 0, 0, 0, $4); - /*% - $$ = params_new($1, $3, Qnil, Qnil, Qnil, Qnil, escape_Qundef($4)); - %*/ - } - | f_arg ',' f_block_optarg ',' f_arg ',' f_block_kwarg f_kwrest opt_f_block_arg - { - /*%%%*/ - $$ = new_args($1, $3, 0, $5, $7, $8, $9); - /*% - $$ = params_new($1, $3, Qnil, $5, $7, $8, escape_Qundef($9)); - %*/ - } - | f_arg ',' f_block_optarg ',' f_arg ',' f_block_kwarg opt_f_block_arg - { - /*%%%*/ - $$ = new_args($1, $3, 0, $5, $7, 0, $8); - /*% - $$ = params_new($1, $3, Qnil, $5, $7, Qnil, escape_Qundef($8)); - %*/ - } - | f_arg ',' f_block_optarg ',' f_arg opt_f_block_arg - { - /*%%%*/ - $$ = new_args($1, $3, 0, $5, 0, 0, $6); - /*% - $$ = params_new($1, $3, Qnil, $5, Qnil, Qnil, escape_Qundef($6)); - %*/ - } - | f_arg ',' f_rest_arg ',' f_block_kwarg f_kwrest opt_f_block_arg - { - /*%%%*/ - $$ = new_args($1, 0, $3, 0, $5, $6, $7); - /*% - $$ = params_new($1, Qnil, $3, Qnil, $5, $6, escape_Qundef($7)); - %*/ - } - | f_arg ',' f_rest_arg ',' f_block_kwarg opt_f_block_arg - { - /*%%%*/ - $$ = new_args($1, 0, $3, 0, $5, 0, $6); - /*% - $$ = params_new($1, Qnil, $3, Qnil, $5, Qnil, escape_Qundef($6)); - %*/ - } - | f_arg ',' f_rest_arg opt_f_block_arg - { - /*%%%*/ - $$ = new_args($1, 0, $3, 0, 0, 0, $4); - /*% - $$ = params_new($1, Qnil, $3, Qnil, Qnil, Qnil, escape_Qundef($4)); - %*/ - } - | f_arg ',' - { - /*%%%*/ - $$ = new_args($1, 0, 1, 0, 0, 0, 0); - /*% - $$ = params_new($1, Qnil, Qnil, Qnil, Qnil, Qnil, Qnil); - dispatch1(excessed_comma, $$); - %*/ - } - | f_arg ',' f_rest_arg ',' f_arg ',' f_block_kwarg f_kwrest opt_f_block_arg - { - /*%%%*/ - $$ = new_args($1, 0, $3, $5, $7, $8, $9); - /*% - $$ = params_new($1, Qnil, $3, $5, $7, $8, escape_Qundef($9)); - %*/ - } - | f_arg ',' f_rest_arg ',' f_arg ',' f_block_kwarg opt_f_block_arg - { - /*%%%*/ - $$ = new_args($1, 0, $3, $5, $7, 0, $8); - /*% - $$ = params_new($1, Qnil, $3, $5, $7, Qnil, escape_Qundef($8)); - %*/ - } - | f_arg ',' f_rest_arg ',' f_arg opt_f_block_arg - { - /*%%%*/ - $$ = new_args($1, 0, $3, $5, 0, 0, $6); - /*% - $$ = params_new($1, Qnil, $3, $5, Qnil, Qnil, escape_Qundef($6)); - %*/ - } - | f_arg ',' f_block_kwarg f_kwrest opt_f_block_arg - { - /*%%%*/ - $$ = new_args($1, 0, 0, 0, $3, $4, $5); - /*% - $$ = params_new($1, Qnil,Qnil, Qnil, $3, $4, escape_Qundef($5)); - %*/ - } - | f_arg ',' f_block_kwarg opt_f_block_arg - { - /*%%%*/ - $$ = new_args($1, 0, 0, 0, $3, 0, $4); - /*% - $$ = params_new($1, Qnil,Qnil, Qnil, $3, Qnil, escape_Qundef($4)); - %*/ - } - | f_arg opt_f_block_arg - { - /*%%%*/ - $$ = new_args($1, 0, 0, 0, 0, 0, $2); - /*% - $$ = params_new($1, Qnil,Qnil, Qnil, Qnil, Qnil, escape_Qundef($2)); - %*/ - } - | f_block_optarg ',' f_rest_arg ',' f_block_kwarg f_kwrest opt_f_block_arg - { - /*%%%*/ - $$ = new_args(0, $1, $3, 0, $5, $6, $7); - /*% - $$ = params_new(Qnil, $1, $3, Qnil, $5, $6, escape_Qundef($7)); - %*/ - } - | f_block_optarg ',' f_rest_arg ',' f_block_kwarg opt_f_block_arg - { - /*%%%*/ - $$ = new_args(0, $1, $3, 0, $5, 0, $6); - /*% - $$ = params_new(Qnil, $1, $3, Qnil, $5, Qnil, escape_Qundef($6)); - %*/ - } - | f_block_optarg ',' f_rest_arg opt_f_block_arg - { - /*%%%*/ - $$ = new_args(0, $1, $3, 0, 0, 0, $4); - /*% - $$ = params_new(Qnil, $1, $3, Qnil, Qnil, Qnil, escape_Qundef($4)); - %*/ - } - | f_block_optarg ',' f_rest_arg ',' f_arg ',' f_block_kwarg f_kwrest opt_f_block_arg - { - /*%%%*/ - $$ = new_args(0, $1, $3, $5, $7, $8, $9); - /*% - $$ = params_new(Qnil, $1, $3, $5, $7, $8, escape_Qundef($9)); - %*/ - } - | f_block_optarg ',' f_rest_arg ',' f_arg ',' f_block_kwarg opt_f_block_arg - { - /*%%%*/ - $$ = new_args(0, $1, $3, $5, $7, 0, $8); - /*% - $$ = params_new(Qnil, $1, $3, $5, $7, Qnil, escape_Qundef($8)); - %*/ - } - | f_block_optarg ',' f_rest_arg ',' f_arg opt_f_block_arg - { - /*%%%*/ - $$ = new_args(0, $1, $3, $5, 0, 0, $6); - /*% - $$ = params_new(Qnil, $1, $3, $5, Qnil, Qnil, escape_Qundef($6)); - %*/ - } - | f_block_optarg ',' f_block_kwarg f_kwrest opt_f_block_arg - { - /*%%%*/ - $$ = new_args(0, $1, 0, 0, $3, $4, $5); - /*% - $$ = params_new(Qnil, $1, Qnil, Qnil, $3, $4, escape_Qundef($5)); - %*/ - } - | f_block_optarg ',' f_block_kwarg opt_f_block_arg - { - /*%%%*/ - $$ = new_args(0, $1, 0, 0, $3, 0, $4); - /*% - $$ = params_new(Qnil, $1, Qnil, Qnil, $3, Qnil, escape_Qundef($4)); - %*/ - } - | f_block_optarg opt_f_block_arg - { - /*%%%*/ - $$ = new_args(0, $1, 0, 0, 0, 0, $2); - /*% - $$ = params_new(Qnil, $1, Qnil, Qnil, Qnil, Qnil, escape_Qundef($2)); - %*/ - } - | f_block_optarg ',' f_arg ',' f_block_kwarg f_kwrest opt_f_block_arg - { - /*%%%*/ - $$ = new_args(0, $1, 0, $3, $5, $6, $7); - /*% - $$ = params_new(Qnil, $1, Qnil, $3, $5, $6, escape_Qundef($7)); - %*/ - } - | f_block_optarg ',' f_arg ',' f_block_kwarg opt_f_block_arg - { - /*%%%*/ - $$ = new_args(0, $1, 0, $3, $5, 0, $6); - /*% - $$ = params_new(Qnil, $1, Qnil, $3, $5, Qnil, escape_Qundef($6)); - %*/ - } - | f_block_optarg ',' f_arg opt_f_block_arg - { - /*%%%*/ - $$ = new_args(0, $1, 0, $3, 0, 0, $4); - /*% - $$ = params_new(Qnil, $1, Qnil, $3, Qnil, Qnil, escape_Qundef($4)); - %*/ - } - | f_rest_arg ',' f_block_kwarg f_kwrest opt_f_block_arg - { - /*%%%*/ - $$ = new_args(0, 0, $1, 0, $3, $4, $5); - /*% - $$ = params_new(Qnil, Qnil, $1, Qnil, $3, $4, escape_Qundef($5)); - %*/ - } - | f_rest_arg ',' f_block_kwarg opt_f_block_arg - { - /*%%%*/ - $$ = new_args(0, 0, $1, 0, $3, 0, $4); - /*% - $$ = params_new(Qnil, Qnil, $1, Qnil, $3, Qnil, escape_Qundef($4)); - %*/ - } - | f_rest_arg opt_f_block_arg - { - /*%%%*/ - $$ = new_args(0, 0, $1, 0, 0, 0, $2); - /*% - $$ = params_new(Qnil, Qnil, $1, Qnil, Qnil, Qnil, escape_Qundef($2)); - %*/ - } - | f_rest_arg ',' f_arg ',' f_block_kwarg f_kwrest opt_f_block_arg - { - /*%%%*/ - $$ = new_args(0, 0, $1, $3, $5, $6, $7); - /*% - $$ = params_new(Qnil, Qnil, $1, $3, $5, $6, escape_Qundef($7)); - %*/ - } - | f_rest_arg ',' f_arg ',' f_block_kwarg opt_f_block_arg - { - /*%%%*/ - $$ = new_args(0, 0, $1, $3, $5, 0, $6); - /*% - $$ = params_new(Qnil, Qnil, $1, $3, $5, Qnil, escape_Qundef($6)); - %*/ - } - | f_rest_arg ',' f_arg opt_f_block_arg - { - /*%%%*/ - $$ = new_args(0, 0, $1, $3, 0, 0, $4); - /*% - $$ = params_new(Qnil, Qnil, $1, $3, Qnil, Qnil, escape_Qundef($4)); - %*/ - } - | f_block_kwarg f_kwrest opt_f_block_arg - { - /*%%%*/ - $$ = new_args(0, 0, 0, 0, $1, $2, $3); - /*% - $$ = params_new(Qnil, Qnil, Qnil, Qnil, $1, $2, escape_Qundef($3)); - %*/ + $$ = new_args_tail($1, $3, $4); } | f_block_kwarg opt_f_block_arg { - /*%%%*/ - $$ = new_args(0, 0, 0, 0, $1, 0, $2); - /*% - $$ = params_new(Qnil, Qnil, Qnil, Qnil, $1, Qnil, escape_Qundef($2)); - %*/ + $$ = new_args_tail($1, Qnone, $2); } - | tPOW tIDENTIFIER opt_f_block_arg + | f_kwrest opt_f_block_arg { - /*%%%*/ - $$ = new_args(0, 0, 0, 0, 0, $2, $3); - /*% - $$ = params_new(Qnil, Qnil, Qnil, Qnil, Qnil, $2, escape_Qundef($3)); - %*/ + $$ = new_args_tail(Qnone, $1, $2); } | f_block_arg { + $$ = new_args_tail(Qnone, Qnone, $1); + } + ; + +opt_block_args_tail : ',' block_args_tail + { + $$ = $2; + } + | /* none */ + { + $$ = new_args_tail(Qnone, Qnone, Qnone); + } + ; +block_param : f_arg ',' f_block_optarg ',' f_rest_arg opt_block_args_tail + { + $$ = new_args($1, $3, $5, Qnone, $6); + } + | f_arg ',' f_block_optarg ',' f_rest_arg ',' f_arg opt_block_args_tail + { + $$ = new_args($1, $3, $5, $7, $8); + } + | f_arg ',' f_block_optarg opt_block_args_tail + { + $$ = new_args($1, $3, Qnone, Qnone, $4); + } + | f_arg ',' f_block_optarg ',' f_arg opt_block_args_tail + { + $$ = new_args($1, $3, Qnone, $5, $6); + } + | f_arg ',' f_rest_arg opt_block_args_tail + { + $$ = new_args($1, Qnone, $3, Qnone, $4); + } + | f_arg ',' + { + $$ = new_args($1, Qnone, 1, Qnone, new_args_tail(Qnone, Qnone, Qnone)); /*%%%*/ - $$ = new_args(0, 0, 0, 0, 0, 0, $1); /*% - $$ = params_new(Qnil, Qnil, Qnil, Qnil, Qnil, Qnil, $1); + dispatch1(excessed_comma, $$); %*/ } + | f_arg ',' f_rest_arg ',' f_arg opt_block_args_tail + { + $$ = new_args($1, Qnone, $3, $5, $6); + } + | f_arg opt_block_args_tail + { + $$ = new_args($1, Qnone, Qnone, Qnone, $2); + } + | f_block_optarg ',' f_rest_arg opt_block_args_tail + { + $$ = new_args(Qnone, $1, $3, Qnone, $4); + } + | f_block_optarg ',' f_rest_arg ',' f_arg opt_block_args_tail + { + $$ = new_args(Qnone, $1, $3, $5, $6); + } + | f_block_optarg opt_block_args_tail + { + $$ = new_args(Qnone, $1, Qnone, Qnone, $2); + } + | f_block_optarg ',' f_arg opt_block_args_tail + { + $$ = new_args(Qnone, $1, Qnone, $3, $4); + } + | f_rest_arg opt_block_args_tail + { + $$ = new_args(Qnone, Qnone, $1, Qnone, $2); + } + | f_rest_arg ',' f_arg opt_block_args_tail + { + $$ = new_args(Qnone, Qnone, $1, $3, $4); + } + | block_args_tail + { + $$ = new_args(Qnone, Qnone, Qnone, Qnone, $1); + } ; opt_block_param : none @@ -4674,357 +4430,94 @@ f_arglist : '(' f_args rparen } ; -f_args : f_arg ',' f_optarg ',' f_rest_arg ',' f_kwarg f_kwrest opt_f_block_arg +args_tail : f_kwarg ',' f_kwrest opt_f_block_arg { - /*%%%*/ - $$ = new_args($1, $3, $5, 0, $7, $8, $9); - /*% - $$ = params_new($1, $3, $5, Qnil, $7, $8, escape_Qundef($9)); - %*/ - } - | f_arg ',' f_optarg ',' f_rest_arg ',' f_kwarg opt_f_block_arg - { - /*%%%*/ - $$ = new_args($1, $3, $5, 0, $7, 0, $8); - /*% - $$ = params_new($1, $3, $5, Qnil, $7, Qnil, escape_Qundef($8)); - %*/ - } - | f_arg ',' f_optarg ',' f_rest_arg opt_f_block_arg - { - /*%%%*/ - $$ = new_args($1, $3, $5, 0, 0, 0, $6); - /*% - $$ = params_new($1, $3, $5, Qnil, Qnil, Qnil, escape_Qundef($6)); - %*/ - } - | f_arg ',' f_optarg ',' f_rest_arg ',' f_arg ',' f_kwarg f_kwrest opt_f_block_arg - { - /*%%%*/ - $$ = new_args($1, $3, $5, $7, $9, $10, $11); - /*% - $$ = params_new($1, $3, $5, $7, $9, $10, escape_Qundef($11)); - %*/ - } - | f_arg ',' f_optarg ',' f_rest_arg ',' f_arg ',' f_kwarg opt_f_block_arg - { - /*%%%*/ - $$ = new_args($1, $3, $5, $7, $9, 0, $10); - /*% - $$ = params_new($1, $3, $5, $7, $9, Qnil, escape_Qundef($10)); - %*/ - } - | f_arg ',' f_optarg ',' f_rest_arg ',' f_arg opt_f_block_arg - { - /*%%%*/ - $$ = new_args($1, $3, $5, $7, 0, 0, $8); - /*% - $$ = params_new($1, $3, $5, $7, Qnil, Qnil, escape_Qundef($8)); - %*/ - } - | f_arg ',' f_optarg ',' f_kwarg f_kwrest opt_f_block_arg - { - /*%%%*/ - $$ = new_args($1, $3, 0, 0, $5, $6, $7); - /*% - $$ = params_new($1, $3, Qnil, Qnil, $5, $6, escape_Qundef($7)); - %*/ - } - | f_arg ',' f_optarg ',' f_kwarg opt_f_block_arg - { - /*%%%*/ - $$ = new_args($1, $3, 0, 0, $5, 0, $6); - /*% - $$ = params_new($1, $3, Qnil, Qnil, $5, Qnil, escape_Qundef($6)); - %*/ - } - | f_arg ',' f_optarg opt_f_block_arg - { - /*%%%*/ - $$ = new_args($1, $3, 0, 0, 0, 0, $4); - /*% - $$ = params_new($1, $3, Qnil, Qnil, Qnil, Qnil, escape_Qundef($4)); - %*/ - } - | f_arg ',' f_optarg ',' f_arg ',' f_kwarg f_kwrest opt_f_block_arg - { - /*%%%*/ - $$ = new_args($1, $3, 0, $5, $7, $8, $9); - /*% - $$ = params_new($1, $3, Qnil, $5, $7, $8, escape_Qundef($9)); - %*/ - } - | f_arg ',' f_optarg ',' f_arg ',' f_kwarg opt_f_block_arg - { - /*%%%*/ - $$ = new_args($1, $3, 0, $5, $7, 0, $8); - /*% - $$ = params_new($1, $3, Qnil, $5, $7, Qnil, escape_Qundef($8)); - %*/ - } - | f_arg ',' f_optarg ',' f_arg opt_f_block_arg - { - /*%%%*/ - $$ = new_args($1, $3, 0, $5, 0, 0, $6); - /*% - $$ = params_new($1, $3, Qnil, $5, Qnil, Qnil, escape_Qundef($6)); - %*/ - } - | f_arg ',' f_rest_arg ',' f_kwarg f_kwrest opt_f_block_arg - { - /*%%%*/ - $$ = new_args($1, 0, $3, 0, $5, $6, $7); - /*% - $$ = params_new($1, Qnil, $3, Qnil, $5, $6, escape_Qundef($7)); - %*/ - } - | f_arg ',' f_rest_arg ',' f_kwarg opt_f_block_arg - { - /*%%%*/ - $$ = new_args($1, 0, $3, 0, $5, 0, $6); - /*% - $$ = params_new($1, Qnil, $3, Qnil, $5, Qnil, escape_Qundef($6)); - %*/ - } - | f_arg ',' f_rest_arg opt_f_block_arg - { - /*%%%*/ - $$ = new_args($1, 0, $3, 0, 0, 0, $4); - /*% - $$ = params_new($1, Qnil, $3, Qnil, Qnil, Qnil, escape_Qundef($4)); - %*/ - } - | f_arg ',' f_rest_arg ',' f_arg ',' f_kwarg f_kwrest opt_f_block_arg - { - /*%%%*/ - $$ = new_args($1, 0, $3, $5, $7, $8, $9); - /*% - $$ = params_new($1, Qnil, $3, $5, $7, $8, escape_Qundef($9)); - %*/ - } - | f_arg ',' f_rest_arg ',' f_arg ',' f_kwarg opt_f_block_arg - { - /*%%%*/ - $$ = new_args($1, 0, $3, $5, $7, 0, $8); - /*% - $$ = params_new($1, Qnil, $3, $5, $7, Qnil, escape_Qundef($8)); - %*/ - } - | f_arg ',' f_rest_arg ',' f_arg opt_f_block_arg - { - /*%%%*/ - $$ = new_args($1, 0, $3, $5, 0, 0, $6); - /*% - $$ = params_new($1, Qnil, $3, $5, Qnil, Qnil, escape_Qundef($6)); - %*/ - } - | f_arg ',' f_kwarg f_kwrest opt_f_block_arg - { - /*%%%*/ - $$ = new_args($1, 0, 0, 0, $3, $4, $5); - /*% - $$ = params_new($1, Qnil, Qnil, Qnil, $3, $4, escape_Qundef($5)); - %*/ - } - | f_arg ',' f_kwarg opt_f_block_arg - { - /*%%%*/ - $$ = new_args($1, 0, 0, 0, $3, 0, $4); - /*% - $$ = params_new($1, Qnil, Qnil, Qnil, $3, Qnil, escape_Qundef($4)); - %*/ - } - | f_arg opt_f_block_arg - { - /*%%%*/ - $$ = new_args($1, 0, 0, 0, 0, 0, $2); - /*% - $$ = params_new($1, Qnil, Qnil, Qnil, Qnil, Qnil, escape_Qundef($2)); - %*/ - } - | f_optarg ',' f_rest_arg ',' f_kwarg f_kwrest opt_f_block_arg - { - /*%%%*/ - $$ = new_args(0, $1, $3, 0, $5, $6, $7); - /*% - $$ = params_new(Qnil, $1, $3, Qnil, $5, $6, escape_Qundef($7)); - %*/ - } - | f_optarg ',' f_rest_arg ',' f_kwarg opt_f_block_arg - { - /*%%%*/ - $$ = new_args(0, $1, $3, 0, $5, 0, $6); - /*% - $$ = params_new(Qnil, $1, $3, Qnil, $5, Qnil, escape_Qundef($6)); - %*/ - } - | f_optarg ',' f_rest_arg opt_f_block_arg - { - /*%%%*/ - $$ = new_args(0, $1, $3, 0, 0, 0, $4); - /*% - $$ = params_new(Qnil, $1, $3, Qnil, Qnil, Qnil, escape_Qundef($4)); - %*/ - } - | f_optarg ',' f_rest_arg ',' f_arg ',' f_kwarg f_kwrest opt_f_block_arg - { - /*%%%*/ - $$ = new_args(0, $1, $3, $5, $7, $8, $9); - /*% - $$ = params_new(Qnil, $1, $3, $5, $7, $8, escape_Qundef($9)); - %*/ - } - | f_optarg ',' f_rest_arg ',' f_arg ',' f_kwarg opt_f_block_arg - { - /*%%%*/ - $$ = new_args(0, $1, $3, $5, $7, 0, $8); - /*% - $$ = params_new(Qnil, $1, $3, $5, $7, Qnil, escape_Qundef($8)); - %*/ - } - | f_optarg ',' f_rest_arg ',' f_arg opt_f_block_arg - { - /*%%%*/ - $$ = new_args(0, $1, $3, $5, 0, 0, $6); - /*% - $$ = params_new(Qnil, $1, $3, $5, Qnil, Qnil, escape_Qundef($6)); - %*/ - } - | f_optarg ',' f_kwarg f_kwrest opt_f_block_arg - { - /*%%%*/ - $$ = new_args(0, $1, 0, 0, $3, $4, $5); - /*% - $$ = params_new(Qnil, $1, Qnil, Qnil, $3, $4, escape_Qundef($5)); - %*/ - } - | f_optarg ',' f_kwarg opt_f_block_arg - { - /*%%%*/ - $$ = new_args(0, $1, 0, 0, $3, 0, $4); - /*% - $$ = params_new(Qnil, $1, Qnil, Qnil, $3, Qnil, escape_Qundef($4)); - %*/ - } - | f_optarg opt_f_block_arg - { - /*%%%*/ - $$ = new_args(0, $1, 0, 0, 0, 0, $2); - /*% - $$ = params_new(Qnil, $1, Qnil, Qnil, Qnil, Qnil, escape_Qundef($2)); - %*/ - } - | f_optarg ',' f_arg ',' f_kwarg f_kwrest opt_f_block_arg - { - /*%%%*/ - $$ = new_args(0, $1, 0, $3, $5, $6, $7); - /*% - $$ = params_new(Qnil, $1, Qnil, $3, $5, $6, escape_Qundef($7)); - %*/ - } - | f_optarg ',' f_arg ',' f_kwarg opt_f_block_arg - { - /*%%%*/ - $$ = new_args(0, $1, 0, $3, $5, 0, $6); - /*% - $$ = params_new(Qnil, $1, Qnil, $3, $5, Qnil, escape_Qundef($6)); - %*/ - } - | f_optarg ',' f_arg opt_f_block_arg - { - /*%%%*/ - $$ = new_args(0, $1, 0, $3, 0, 0, $4); - /*% - $$ = params_new(Qnil, $1, Qnil, $3, Qnil, Qnil, escape_Qundef($4)); - %*/ - } - | f_rest_arg ',' f_kwarg f_kwrest opt_f_block_arg - { - /*%%%*/ - $$ = new_args(0, 0, $1, 0, $3, $4, $5); - /*% - $$ = params_new(Qnil, Qnil, $1, Qnil, $3, $4, escape_Qundef($5)); - %*/ - } - | f_rest_arg ',' f_kwarg opt_f_block_arg - { - /*%%%*/ - $$ = new_args(0, 0, $1, 0, $3, 0, $4); - /*% - $$ = params_new(Qnil, Qnil, $1, Qnil, $3, Qnil, escape_Qundef($4)); - %*/ - } - | f_rest_arg opt_f_block_arg - { - /*%%%*/ - $$ = new_args(0, 0, $1, 0, 0, 0, $2); - /*% - $$ = params_new(Qnil, Qnil, $1, Qnil, Qnil, Qnil, escape_Qundef($2)); - %*/ - } - | f_rest_arg ',' f_arg ',' f_kwarg f_kwrest opt_f_block_arg - { - /*%%%*/ - $$ = new_args(0, 0, $1, $3, $5, $6, $7); - /*% - $$ = params_new(Qnil, Qnil, $1, $3, $5, $6, escape_Qundef($7)); - %*/ - } - | f_rest_arg ',' f_arg ',' f_kwarg opt_f_block_arg - { - /*%%%*/ - $$ = new_args(0, 0, $1, $3, $5, 0, $6); - /*% - $$ = params_new(Qnil, Qnil, $1, $3, $5, Qnil, escape_Qundef($6)); - %*/ - } - | f_rest_arg ',' f_arg opt_f_block_arg - { - /*%%%*/ - $$ = new_args(0, 0, $1, $3, 0, 0, $4); - /*% - $$ = params_new(Qnil, Qnil, $1, $3, Qnil, Qnil, escape_Qundef($4)); - %*/ - } - | f_kwarg f_kwrest opt_f_block_arg - { - /*%%%*/ - $$ = new_args(0, 0, 0, 0, $1, $2, $3); - /*% - $$ = params_new(Qnil, Qnil, Qnil, Qnil, $1, $2, escape_Qundef($3)); - %*/ + $$ = new_args_tail($1, $3, $4); } | f_kwarg opt_f_block_arg { - /*%%%*/ - $$ = new_args(0, 0, 0, 0, $1, 0, $2); - /*% - $$ = params_new(Qnil, Qnil, Qnil, Qnil, $1, Qnil, escape_Qundef($2)); - %*/ + $$ = new_args_tail($1, Qnone, $2); } - | tPOW tIDENTIFIER opt_f_block_arg + | f_kwrest opt_f_block_arg { - /*%%%*/ - $$ = new_args(0, 0, 0, 0, 0, $2, $3); - /*% - $$ = params_new(Qnil, Qnil, Qnil, Qnil, Qnil, $2, escape_Qundef($3)); - %*/ + $$ = new_args_tail(Qnone, $1, $2); } | f_block_arg { - /*%%%*/ - $$ = new_args(0, 0, 0, 0, 0, 0, $1); - /*% - $$ = params_new(Qnil, Qnil, Qnil, Qnil, Qnil, Qnil, $1); - %*/ + $$ = new_args_tail(Qnone, Qnone, $1); + } + ; + +opt_args_tail : ',' args_tail + { + $$ = $2; } | /* none */ { - /*%%%*/ - $$ = new_args(0, 0, 0, 0, 0, 0, 0); - /*% - $$ = params_new(Qnil, Qnil, Qnil, Qnil, Qnil, Qnil, Qnil); - %*/ + $$ = new_args_tail(Qnone, Qnone, Qnone); + } + ; + +f_args : f_arg ',' f_optarg ',' f_rest_arg opt_args_tail + { + $$ = new_args($1, $3, $5, Qnone, $6); + } + | f_arg ',' f_optarg ',' f_rest_arg ',' f_arg opt_args_tail + { + $$ = new_args($1, $3, $5, $7, $8); + } + | f_arg ',' f_optarg opt_args_tail + { + $$ = new_args($1, $3, Qnone, Qnone, $4); + } + | f_arg ',' f_optarg ',' f_arg opt_args_tail + { + $$ = new_args($1, $3, Qnone, $5, $6); + } + | f_arg ',' f_rest_arg opt_args_tail + { + $$ = new_args($1, Qnone, $3, Qnone, $4); + } + | f_arg ',' f_rest_arg ',' f_arg opt_args_tail + { + $$ = new_args($1, Qnone, $3, $5, $6); + } + | f_arg opt_args_tail + { + $$ = new_args($1, Qnone, Qnone, Qnone, $2); + } + | f_optarg ',' f_rest_arg opt_args_tail + { + $$ = new_args(Qnone, $1, $3, Qnone, $4); + } + | f_optarg ',' f_rest_arg ',' f_arg opt_args_tail + { + $$ = new_args(Qnone, $1, $3, $5, $6); + } + | f_optarg opt_args_tail + { + $$ = new_args(Qnone, $1, Qnone, Qnone, $2); + } + | f_optarg ',' f_arg opt_args_tail + { + $$ = new_args(Qnone, $1, Qnone, $3, $4); + } + | f_rest_arg opt_args_tail + { + $$ = new_args(Qnone, Qnone, $1, Qnone, $2); + } + | f_rest_arg ',' f_arg opt_args_tail + { + $$ = new_args(Qnone, Qnone, $1, $3, $4); + } + | args_tail + { + $$ = new_args(Qnone, Qnone, Qnone, Qnone, $1); + } + | /* none */ + { + $$ = new_args_tail(Qnone, Qnone, Qnone); + $$ = new_args(Qnone, Qnone, Qnone, Qnone, $$); } ; @@ -5195,9 +4688,9 @@ f_kwarg : f_kw } ; -f_kwrest : ',' tPOW tIDENTIFIER +f_kwrest : tPOW tIDENTIFIER { - $$ = $3; + $$ = $2; } ; @@ -9684,13 +9177,12 @@ arg_blk_pass(NODE *node1, NODE *node2) return node1; } + static NODE* -new_args_gen(struct parser_params *parser, NODE *m, NODE *o, ID r, NODE *p, NODE *k, ID kr, ID b) +new_args_gen(struct parser_params *parser, NODE *m, NODE *o, ID r, NODE *p, NODE *tail) { int saved_line = ruby_sourceline; - struct rb_args_info *args; - - args = ALLOC(struct rb_args_info); + struct rb_args_info *args = tail->nd_ainfo; args->pre_args_num = m ? rb_long2int(m->nd_plen) : 0; args->pre_init = m ? m->nd_next : 0; @@ -9700,13 +9192,31 @@ new_args_gen(struct parser_params *parser, NODE *m, NODE *o, ID r, NODE *p, NODE args->first_post_arg = p ? p->nd_pid : 0; args->rest_arg = r; - args->block_arg = b; args->opt_args = o; + + ruby_sourceline = saved_line; + + return tail; +} + +static NODE* +new_args_tail_gen(struct parser_params *parser, NODE *k, ID kr, ID b) +{ + int saved_line = ruby_sourceline; + struct rb_args_info *args; + NODE *kw_rest_arg = 0; + + args = ALLOC(struct rb_args_info); + + args->block_arg = b; args->kw_args = k; if (k && !kr) kr = internal_id(); - arg_var(kr); - args->kw_rest_arg = NEW_DVAR(kr); + if (kr) { + arg_var(kr); + kw_rest_arg = NEW_DVAR(kr); + } + args->kw_rest_arg = kw_rest_arg; ruby_sourceline = saved_line; return NEW_NODE(NODE_ARGS, 0, 0, args); diff --git a/test/ruby/test_syntax.rb b/test/ruby/test_syntax.rb index 532b989bbd..5ede83caba 100644 --- a/test/ruby/test_syntax.rb +++ b/test/ruby/test_syntax.rb @@ -79,8 +79,13 @@ class TestSyntax < Test::Unit::TestCase def test_keyword_rest bug5989 = '[ruby-core:42455]' - assert_valid_syntax("def kwrest_test(**a) end", __FILE__) - assert_valid_syntax("def kwrest_test(**a, &b) end", __FILE__) + assert_valid_syntax("def kwrest_test(**a) a; end", __FILE__) + assert_valid_syntax("def kwrest_test2(**a, &b) end", __FILE__) + o = Object.new + def o.kw(**a) a end + assert_equal({}, o.kw) + assert_equal({foo: 1}, o.kw(foo: 1)) + assert_equal({foo: 1, bar: 2}, o.kw(foo: 1, bar: 2)) end private diff --git a/vm_insnhelper.c b/vm_insnhelper.c index a123171580..5f7de4a199 100644 --- a/vm_insnhelper.c +++ b/vm_insnhelper.c @@ -177,7 +177,7 @@ vm_callee_setup_arg_complex(rb_thread_t *th, const rb_iseq_t * iseq, if (iseq->arg_keyword != -1) { int i, j; - if (argc > 0) keyword_hash = rb_check_convert_type(argv[argc-1], T_HASH, "Hash", "to_hash"); + if (argc > 0) keyword_hash = rb_check_hash_type(argv[argc-1]); if (!NIL_P(keyword_hash)) { argc--; keyword_hash = rb_hash_dup(keyword_hash);