From a0a2c144b8b078cea668a703e2308ea64d4eb161 Mon Sep 17 00:00:00 2001 From: mame Date: Mon, 26 Dec 2011 14:20:09 +0000 Subject: * vm_core.h (struct rb_iseq_struct), compile.c (iseq_set_arguments, iseq_compile_each), vm_insnhelper.c (vm_callee_setup_arg_complex): implement keyword arguments. See [ruby-core:40290] The feature is promised to be included in 2.0, but the detail spec is still under discussion; this commit is a springboard for further discussion. Please try it and give us feedback. This commit includes fixes for some problems reported by Benoit Daloze [ruby-core:40518] and Marc-Andre Lafortune [ruby-core:41772]. * iseq.c (iseq_free, prepare_iseq_build): bookkeeping. * test/ruby/test_keyword.rb: add tests for keyword arguments. * test/ripper/dummyparser.rb (class DummyParser): temporal fix for ripper test. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@34136 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- compile.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 68 insertions(+), 2 deletions(-) (limited to 'compile.c') diff --git a/compile.c b/compile.c index 38139f110b..31d9ad2d9b 100644 --- a/compile.c +++ b/compile.c @@ -1127,6 +1127,36 @@ iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *optargs, NODE *node_args) iseq->arg_opts = 0; } + if (args->kw_args) { + NODE *node = args->kw_args; + VALUE keywords = rb_ary_tmp_new(1); + int i = 0, j; + + iseq->arg_keyword = get_dyna_var_idx_at_raw(iseq, args->kw_rest_arg->nd_vid); + COMPILE(optargs, "kwarg", args->kw_rest_arg); + while (node) { + rb_ary_push(keywords, INT2FIX(node->nd_body->nd_vid)); + COMPILE_POPED(optargs, "kwarg", node); /* nd_type(node) == NODE_KW_ARG */ + node = node->nd_next; + i += 1; + } + if ((args->kw_rest_arg->nd_vid & ID_SCOPE_MASK) == ID_JUNK) { + iseq->arg_keywords = i; + iseq->arg_keyword_table = ALLOC_N(ID, i); + for (j = 0; j < i; j++) { + iseq->arg_keyword_table[j] = FIX2INT(RARRAY_PTR(keywords)[j]); + } + } + else { + iseq->arg_keywords = 0; + iseq->arg_keyword_table = 0; + } + ADD_INSN(optargs, nd_line(args->kw_args), pop); + } + else { + iseq->arg_keyword = -1; + } + if (args->pre_init) { /* m_init */ COMPILE_POPED(optargs, "init arguments (m)", args->pre_init); } @@ -1151,11 +1181,15 @@ iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *optargs, NODE *node_args) } if (iseq->arg_opts != 0 || iseq->arg_post_len != 0 || - iseq->arg_rest != -1 || iseq->arg_block != -1) { + iseq->arg_rest != -1 || iseq->arg_block != -1 || + iseq->arg_keyword != -1) { iseq->arg_simple = 0; /* set arg_size: size of arguments */ - if (iseq->arg_block != -1) { + if (iseq->arg_keyword != -1) { + iseq->arg_size = iseq->arg_keyword + 1; + } + else if (iseq->arg_block != -1) { iseq->arg_size = iseq->arg_block + 1; } else if (iseq->arg_post_len) { @@ -4919,6 +4953,38 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped) } break; } + case NODE_KW_ARG:{ + LABEL *default_label = NEW_LABEL(nd_line(node)); + LABEL *end_label = NEW_LABEL(nd_line(node)); + int idx, lv, ls; + ID id = node->nd_body->nd_vid; + + ADD_INSN(ret, nd_line(node), dup); + ADD_INSN1(ret, nd_line(node), putobject, ID2SYM(id)); + ADD_SEND(ret, nd_line(node), ID2SYM(rb_intern("key?")), INT2FIX(1)); + ADD_INSNL(ret, nd_line(node), branchunless, default_label); + ADD_INSN(ret, nd_line(node), dup); + 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))); + } + ADD_INSNL(ret, nd_line(node), jump, end_label); + ADD_LABEL(ret, default_label); + COMPILE_POPED(ret, "keyword default argument", node->nd_body); + ADD_LABEL(ret, end_label); + break; + } case NODE_DSYM:{ compile_dstr(iseq, ret, node); if (!poped) { -- cgit v1.2.3