From c23f1f56c66c6121597b315b8fe05198d1f90c28 Mon Sep 17 00:00:00 2001 From: yugui Date: Mon, 27 Oct 2008 13:35:46 +0000 Subject: * vm_insnhelper.c (vm_yield_setup_args): supports optional parameters. Fixed [ruby-core:19503]. * vm_insnhelper.c (vm_yield_setup_block_args): a new function. extracted from vm_yield_setup_args. * vm_insnhelper.c (vm_yield_setup_block_args_complex): ditto. * test/ruby/test_proc.rb: added tests for arguments on a Proc from Kernel#proc called. git-svn-id: http://svn.ruby-lang.org/repos/ruby/trunk@19968 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- vm_insnhelper.c | 241 ++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 145 insertions(+), 96 deletions(-) (limited to 'vm_insnhelper.c') diff --git a/vm_insnhelper.c b/vm_insnhelper.c index 2e862492f..5c4930499 100644 --- a/vm_insnhelper.c +++ b/vm_insnhelper.c @@ -678,125 +678,174 @@ vm_yield_with_cfunc(rb_thread_t *th, const rb_block_t *block, return val; } + +/*-- + * @brief on supplied all of optional, rest and post parameters. + * @pre iseq is block style (not lambda style) + */ static inline int -vm_yield_setup_args(rb_thread_t * const th, const rb_iseq_t *iseq, - int orig_argc, VALUE *argv, - const rb_block_t *blockptr, int lambda) +vm_yield_setup_block_args_complex(rb_thread_t *th, const rb_iseq_t * iseq, + int argc, VALUE * argv) { - if (0) { /* for debug */ - printf(" argc: %d\n", orig_argc); - printf("iseq argc: %d\n", iseq->argc); - printf("iseq opts: %d\n", iseq->arg_opts); - printf("iseq rest: %d\n", iseq->arg_rest); - printf("iseq post: %d\n", iseq->arg_post_len); - printf("iseq blck: %d\n", iseq->arg_block); - printf("iseq smpl: %d\n", iseq->arg_simple); - printf(" lambda: %s\n", lambda ? "true" : "false"); + int opt_pc = 0; + int i; + const int m = iseq->argc; + const int r = iseq->arg_rest; + int len = iseq->arg_post_len; + int start = iseq->arg_post_start; + int rsize = argc > m ? argc - m : 0; /* # of arguments which did not consumed yet */ + int psize = rsize > len ? len : rsize; /* # of post arguments */ + int osize = 0; /* # of opt arguments */ + VALUE ary; + + /* reserves arguments for post parameters */ + rsize -= psize; + + if (iseq->arg_opts) { + const int opts = iseq->arg_opts - 1; + if (rsize > opts) { + osize = opts; + opt_pc = iseq->arg_opt_table[opts]; + } + else { + osize = rsize; + opt_pc = iseq->arg_opt_table[rsize]; + } } + rsize -= osize; - if (lambda) { - /* call as method */ - int opt_pc; - VM_CALLEE_SETUP_ARG(opt_pc, th, iseq, orig_argc, argv, &blockptr); - return opt_pc; + if (0) { + printf(" argc: %d\n", argc); + printf(" len: %d\n", len); + printf("start: %d\n", start); + printf("rsize: %d\n", rsize); + } + + if (r == -1) { + /* copy post argument */ + MEMMOVE(&argv[start], &argv[m+osize], VALUE, psize); } else { - int i; - int argc = orig_argc; - const int m = iseq->argc; - VALUE ary; + ary = rb_ary_new4(rsize, &argv[r]); - th->mark_stack_len = argc; + /* copy post argument */ + MEMMOVE(&argv[start], &argv[m+rsize+osize], VALUE, psize); + argv[r] = ary; + } - /* - * yield [1, 2] - * => {|a|} => a = [1, 2] - * => {|a, b|} => a, b = [1, 2] - */ - if (!(iseq->arg_simple & 0x02) && - (m + iseq->arg_post_len) > 0 && - argc == 1 && !NIL_P(ary = rb_check_array_type(argv[0]))) { - th->mark_stack_len = argc = RARRAY_LEN(ary); + for (i=psize; icfp, argc); + return opt_pc; +} - MEMCPY(argv, RARRAY_PTR(ary), VALUE, argc); - } +static inline int +vm_yield_setup_block_args(rb_thread_t *th, const rb_iseq_t * iseq, + int orig_argc, VALUE * argv, + const rb_block_t *blockptr) +{ + int i; + int argc = orig_argc; + const int m = iseq->argc; + VALUE ary; + int opt_pc = 0; - for (i=argc; imark_stack_len = argc; - if (iseq->arg_rest == -1) { - const int arg_size = iseq->arg_size; - if (arg_size < argc) { - /* - * yield 1, 2 - * => {|a|} # truncate - */ - th->mark_stack_len = argc = arg_size; - } - } - else { - int r = iseq->arg_rest; + /* + * yield [1, 2] + * => {|a|} => a = [1, 2] + * => {|a, b|} => a, b = [1, 2] + */ + if (!(iseq->arg_simple & 0x02) && /* exclude {|a|} */ + (m + iseq->arg_post_len) > 0 && /* this process is meaningful */ + argc == 1 && !NIL_P(ary = rb_check_array_type(argv[0]))) { /* rhs is only an array */ + th->mark_stack_len = argc = RARRAY_LEN(ary); - if (iseq->arg_post_len) { - int len = iseq->arg_post_len; - int start = iseq->arg_post_start; - int rsize = argc > m ? argc - m : 0; - int psize = rsize; - VALUE ary; + CHECK_STACK_OVERFLOW(th->cfp, argc); - if (psize > len) psize = len; + MEMCPY(argv, RARRAY_PTR(ary), VALUE, argc); + } - ary = rb_ary_new4(rsize - psize, &argv[r]); + for (i=argc; iarg_rest == -1 && iseq->arg_opts == 0) { + const int arg_size = iseq->arg_size; + if (arg_size < argc) { + /* + * yield 1, 2 + * => {|a|} # truncate + */ + th->mark_stack_len = argc = arg_size; + } + } + else { + int r = iseq->arg_rest; - /* copy post argument */ - MEMMOVE(&argv[start], &argv[r + rsize - psize], VALUE, psize); + if (iseq->arg_post_len || + iseq->arg_opts) { /* TODO: implement simple version for (iseq->arg_post_len==0 && iseq->arg_opts > 0) */ + opt_pc = vm_yield_setup_block_args_complex(th, iseq, argc, argv); + } + else { + if (argc < r) { + /* yield 1 + * => {|a, b, *r|} + */ + for (i=argc; i {|a, b, *r|} - */ - for (i=argc; imark_stack_len = iseq->arg_size; + } - th->mark_stack_len = iseq->arg_size; - } + /* {|&b|} */ + if (iseq->arg_block != -1) { + VALUE procval = Qnil; - /* {|&b|} */ - if (iseq->arg_block != -1) { - VALUE procval = Qnil; + if (blockptr) { + procval = blockptr->proc; + } - if (blockptr) { - procval = blockptr->proc; - } + argv[iseq->arg_block] = procval; + } - argv[iseq->arg_block] = procval; - } + th->mark_stack_len = 0; + return opt_pc; +} - th->mark_stack_len = 0; - return 0; +static inline int +vm_yield_setup_args(rb_thread_t * const th, const rb_iseq_t *iseq, + int argc, VALUE *argv, + const rb_block_t *blockptr, int lambda) +{ + if (0) { /* for debug */ + printf(" argc: %d\n", argc); + printf("iseq argc: %d\n", iseq->argc); + printf("iseq opts: %d\n", iseq->arg_opts); + printf("iseq rest: %d\n", iseq->arg_rest); + printf("iseq post: %d\n", iseq->arg_post_len); + printf("iseq blck: %d\n", iseq->arg_block); + printf("iseq smpl: %d\n", iseq->arg_simple); + printf(" lambda: %s\n", lambda ? "true" : "false"); + } + + if (lambda) { + /* call as method */ + int opt_pc; + VM_CALLEE_SETUP_ARG(opt_pc, th, iseq, argc, argv, &blockptr); + return opt_pc; + } + else { + return vm_yield_setup_block_args(th, iseq, argc, argv, blockptr); } } -- cgit