diff options
author | nobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2013-04-12 06:21:35 +0000 |
---|---|---|
committer | nobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2013-04-12 06:21:35 +0000 |
commit | 2674f9a8158b521d22867415db5fd49ebe615c98 (patch) | |
tree | af1461e3994179ba6dbd5e6f3c759be4dc130089 /vm_insnhelper.c | |
parent | 9ef4e13459c95922e7384194c90b91bf67dd785a (diff) |
vm_insnhelper.c: non-symbol key
* vm_insnhelper.c (vm_callee_setup_keyword_arg): non-symbol key is not
a keyword argument, keep it as an positional argument.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@40260 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'vm_insnhelper.c')
-rw-r--r-- | vm_insnhelper.c | 44 |
1 files changed, 38 insertions, 6 deletions
diff --git a/vm_insnhelper.c b/vm_insnhelper.c index b1c48faf03..d4d0d45ef4 100644 --- a/vm_insnhelper.c +++ b/vm_insnhelper.c @@ -1070,24 +1070,56 @@ vm_caller_setup_args(const rb_thread_t *th, rb_control_frame_t *cfp, rb_call_inf } } +static int +separate_symbol(st_data_t key, st_data_t value, st_data_t arg) +{ + VALUE *kwdhash = (VALUE *)arg; + + if (!SYMBOL_P(key)) kwdhash++; + if (!*kwdhash) *kwdhash = rb_hash_new(); + rb_hash_aset(*kwdhash, (VALUE)key, (VALUE)value); + return ST_CONTINUE; +} + +static VALUE +extract_keywords(VALUE *orighash) +{ + VALUE parthash[2] = {0, 0}; + VALUE hash = *orighash; + + if (RHASH_EMPTY_P(hash)) { + *orighash = 0; + return hash; + } + st_foreach(RHASH_TBL(hash), separate_symbol, (st_data_t)&parthash); + *orighash = parthash[1]; + return parthash[0]; +} + static inline int vm_callee_setup_keyword_arg(const rb_iseq_t *iseq, int argc, VALUE *orig_argv, VALUE *kwd) { - VALUE keyword_hash; + VALUE keyword_hash, orig_hash; int i, j; if (argc > 0 && - !NIL_P(keyword_hash = rb_check_hash_type(orig_argv[argc-1]))) { - argc--; - keyword_hash = rb_hash_dup(keyword_hash); + !NIL_P(orig_hash = rb_check_hash_type(orig_argv[argc-1])) && + (keyword_hash = extract_keywords(&orig_hash)) != 0) { + if (!orig_hash) { + argc--; + } + else { + orig_argv[argc-1] = orig_hash; + } i = 0; if (iseq->arg_keyword_required) { VALUE missing = Qnil; for (; i < iseq->arg_keyword_required; i++) { - if (st_lookup(RHASH_TBL(keyword_hash), ID2SYM(iseq->arg_keyword_table[i]), 0)) + VALUE keyword = ID2SYM(iseq->arg_keyword_table[i]); + if (st_lookup(RHASH_TBL(keyword_hash), (st_data_t)keyword, 0)) continue; if (NIL_P(missing)) missing = rb_ary_tmp_new(1); - rb_ary_push(missing, ID2SYM(iseq->arg_keyword_table[i])); + rb_ary_push(missing, keyword); } if (!NIL_P(missing)) { keyword_error("missing", missing); |