summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2013-04-12 06:21:35 +0000
committernobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2013-04-12 06:21:35 +0000
commit2674f9a8158b521d22867415db5fd49ebe615c98 (patch)
treeaf1461e3994179ba6dbd5e6f3c759be4dc130089
parent9ef4e13459c95922e7384194c90b91bf67dd785a (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
-rw-r--r--ChangeLog5
-rw-r--r--test/ruby/test_keyword.rb1
-rw-r--r--vm_insnhelper.c44
3 files changed, 44 insertions, 6 deletions
diff --git a/ChangeLog b/ChangeLog
index 9a7feef0e8..391d1d55db 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+Fri Apr 12 15:21:24 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * vm_insnhelper.c (vm_callee_setup_keyword_arg): non-symbol key is not
+ a keyword argument, keep it as an positional argument.
+
Fri Apr 12 11:58:00 2013 Zachary Scott <zachary@zacharyscott.net>
* array.c: Document synonymous methods, by windwiny [GH-277]
diff --git a/test/ruby/test_keyword.rb b/test/ruby/test_keyword.rb
index c9a9ed0a07..ae56757032 100644
--- a/test/ruby/test_keyword.rb
+++ b/test/ruby/test_keyword.rb
@@ -23,6 +23,7 @@ class TestKeywordArguments < Test::Unit::TestCase
def test_f2
assert_equal([:xyz, "foo", 424242], f2(:xyz))
assert_raise(ArgumentError) { f2({}) } # [ruby-dev:46712] [Bug #7529]
+ assert_equal([{"bar"=>42}, "foo", 424242], f2("bar"=>42))
end
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);