diff options
author | mame <mame@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2011-12-26 14:20:09 +0000 |
---|---|---|
committer | mame <mame@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2011-12-26 14:20:09 +0000 |
commit | a0a2c144b8b078cea668a703e2308ea64d4eb161 (patch) | |
tree | 653b4ac1a674c02ea2247f1be1a75b5bc7e60748 /compile.c | |
parent | 1ab3974b0efea5155da005ec08a1feee90023d98 (diff) | |
download | ruby-a0a2c144b8b078cea668a703e2308ea64d4eb161.tar.gz |
* 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 <eregontp AT gmail.com> [ruby-core:40518] and Marc-Andre Lafortune <ruby-core-mailing-list AT marc-andre.ca> [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
Diffstat (limited to 'compile.c')
-rw-r--r-- | compile.c | 70 |
1 files changed, 68 insertions, 2 deletions
@@ -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) { |