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 /vm_insnhelper.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 'vm_insnhelper.c')
-rw-r--r-- | vm_insnhelper.c | 39 |
1 files changed, 39 insertions, 0 deletions
diff --git a/vm_insnhelper.c b/vm_insnhelper.c index 85b5e6ee78..9a22741cc3 100644 --- a/vm_insnhelper.c +++ b/vm_insnhelper.c @@ -132,6 +132,15 @@ argument_error(const rb_iseq_t *iseq, int miss_argc, int correct_argc) rb_exc_raise(exc); } +NORETURN(static void unknown_keyword_error(const rb_iseq_t *iseq, VALUE hash)); +static void +unknown_keyword_error(const rb_iseq_t *iseq, VALUE hash) +{ + (void) iseq; + (void) hash; + rb_raise(rb_eArgError, "unknown keyword"); +} + #define VM_CALLEE_SETUP_ARG(ret, th, iseq, orig_argc, orig_argv, block) \ if (LIKELY((iseq)->arg_simple & 0x01)) { \ /* simple check */ \ @@ -153,9 +162,30 @@ vm_callee_setup_arg_complex(rb_thread_t *th, const rb_iseq_t * iseq, int argc = orig_argc; VALUE *argv = orig_argv; rb_num_t opt_pc = 0; + VALUE keyword_hash = Qnil; th->mark_stack_len = argc + iseq->arg_size; + 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 (!NIL_P(keyword_hash)) { + argc--; + keyword_hash = rb_hash_dup(keyword_hash); + if (iseq->arg_keywords) { + for (i = j = 0; i < iseq->arg_keywords; i++) { + if (st_lookup(RHASH_TBL(keyword_hash), ID2SYM(iseq->arg_keyword_table[i]), 0)) j++; + } + if (RHASH_TBL(keyword_hash)->num_entries > (unsigned int) j) { + unknown_keyword_error(iseq, keyword_hash); + } + } + } + else { + keyword_hash = rb_hash_new(); + } + } + /* mandatory */ if (argc < (m + iseq->arg_post_len)) { /* check with post arg */ argument_error(iseq, argc, m + iseq->arg_post_len); @@ -205,6 +235,11 @@ vm_callee_setup_arg_complex(rb_thread_t *th, const rb_iseq_t * iseq, argc = 0; } + /* keyword argument */ + if (iseq->arg_keyword != -1) { + orig_argv[iseq->arg_keyword] = keyword_hash; + } + /* block arguments */ if (block && iseq->arg_block != -1) { VALUE blockval = Qnil; @@ -230,6 +265,10 @@ vm_callee_setup_arg_complex(rb_thread_t *th, const rb_iseq_t * iseq, orig_argv[iseq->arg_block] = blockval; /* Proc or nil */ } + if (iseq->arg_keyword && argc != 0) { + argument_error(iseq, orig_argc, m + iseq->arg_post_len); + } + th->mark_stack_len = 0; return (int)opt_pc; } |