diff options
author | ko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2007-05-01 04:35:58 +0000 |
---|---|---|
committer | ko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2007-05-01 04:35:58 +0000 |
commit | 75d28f887089c8582b63a64cf5df1d0270f15cc1 (patch) | |
tree | 1a274ad80a96f2546c0aba4701fd0c0e78857b5b /compile.c | |
parent | ea2cb282aeba0457aa775d5dbfa1da6810fafa45 (diff) | |
download | ruby-75d28f887089c8582b63a64cf5df1d0270f15cc1.tar.gz |
* yarvcore.h, compile.c (set_arguments): support post arguments.
* test/ruby/test_method.rb: add tests for above.
* test/ruby/test_proc.rb: ditto.
* proc.c: fix an arity bug ([ruby-core:11029]).
* vm.c, vm.h, insns.def, vm_dump.h: fix bmethod process.
* vm.c: support block argument on block parameter.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12231 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'compile.c')
-rw-r--r-- | compile.c | 77 |
1 files changed, 77 insertions, 0 deletions
@@ -849,6 +849,83 @@ set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *optargs, NODE *node_args) if (iseq->arg_rest == -1) { rb_bug("arg_rest: -1"); } + + if (post_len) { + /* + * if rest.length < post_len + * raise ArgumentError + * end + * post1 = rest.shift + * post2 = rest.shift + * ... + * + * #=> yarv insns + * push rest + * call :length + * put 1 + * call :< + * branchunless :success + * put ArgumentsError + * put "wrong number of arugments (%d of %d)" + * call :new, 1 + * call :raise + * success: + * push rest + * call :shift + * set post1 + * push rest + * call :shift + * set post2 + * ... + */ + LABEL *lsuccess = NEW_LABEL(nd_line(node_args)); + int i; + +#define GET_LOCAL(idx) do { \ + if (iseq->type == ISEQ_TYPE_METHOD) { \ + ADD_INSN1(optargs, nd_line(node_args), getlocal, INT2FIX(iseq->local_size - (idx) + 1)); \ + } \ + else { \ + ADD_INSN2(optargs, nd_line(node_args), getdynamic, INT2FIX(iseq->local_size - (idx)), INT2FIX(0)); \ + } \ +} while (0) + +#define SET_LOCAL(idx) do { \ + if (iseq->type == ISEQ_TYPE_METHOD) { \ + ADD_INSN1(optargs, nd_line(node_args), setlocal, INT2FIX(iseq->local_size - (idx) + 1)); \ + } \ + else { \ + ADD_INSN2(optargs, nd_line(node_args), setdynamic, INT2FIX(iseq->local_size - (idx)), INT2FIX(0)); \ + } \ +} while (0) + + GET_LOCAL(iseq->arg_rest); + ADD_SEND (optargs, nd_line(node_args), ID2SYM(idLength), INT2FIX(0)); + ADD_INSN1(optargs, nd_line(node_args), putobject, INT2FIX(1)); + ADD_SEND (optargs, nd_line(node_args), ID2SYM(idLT), INT2FIX(1)); + ADD_INSNL(optargs, nd_line(node_args), branchunless, lsuccess); + ADD_CALL_RECEIVER(optargs, nd_line(node_args)); + + /* error */ + ADD_INSN1(optargs, nd_line(node_args), putobject, rb_eArgError); + ADD_INSN1(optargs, nd_line(node_args), putstring, rb_str_new2("wrong number of arguments")); + ADD_SEND (optargs, nd_line(node_args), ID2SYM(rb_intern("new")), INT2FIX(1)); + ADD_CALL (optargs, nd_line(node_args), ID2SYM(rb_intern("raise")), INT2FIX(1)); + ADD_INSN (optargs, nd_line(node_args), pop); /* dummy */ + + ADD_LABEL(optargs, lsuccess); + + for (i=0; i<post_len; i++) { + GET_LOCAL(iseq->arg_rest); + ADD_SEND (optargs, nd_line(node_args), ID2SYM(rb_intern("pop")), + INT2FIX(0)); + SET_LOCAL(iseq->arg_rest + i + 1); + } + + iseq->arg_post_len = post_len; + } +#undef GET_LOCAL +#undef SET_LOCAL } if (block_id) { |