diff options
author | ko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2007-06-24 07:29:21 +0000 |
---|---|---|
committer | ko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2007-06-24 07:29:21 +0000 |
commit | 68e02f2c2cc98e6ab736b3122aafe7a2398642f6 (patch) | |
tree | 2167a1299cd58748a883b72de1ba8de0b4128df6 /vm.c | |
parent | a5c9bf7d63bff7772d7a3b392e9d5ebe6a0bf479 (diff) | |
download | ruby-68e02f2c2cc98e6ab736b3122aafe7a2398642f6.tar.gz |
* vm.c (callee_setup_arg): added. support correct post arg.
* vm_macro.def (macro_eval_invoke_func): fix to use
callee_setup_arg.
* compile.c (set_arguments): adjust for above changes.
* compile.c (iseq_compile_each): ditto.
* iseq.c (ruby_iseq_disasm): ditto.
* yarvcore.h: add rb_iseq_t#post_arg_start and arg_size.
* bootstraptest/test_method.rb: add post arg tests.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12594 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'vm.c')
-rw-r--r-- | vm.c | 97 |
1 files changed, 97 insertions, 0 deletions
@@ -184,6 +184,103 @@ th_set_eval_stack(rb_thread_t *th, VALUE iseqval) return 0; } +/* return opt_pc */ +static inline int +callee_setup_arg(rb_thread_t *th, rb_iseq_t *iseq, + int argc, VALUE *argv, rb_block_t **block) +{ + const int m = iseq->argc; + const int orig_argc = argc; + + if (iseq->arg_simple) { + /* simple check */ + if (argc != m) { + rb_raise(rb_eArgError, "wrong number of arguments (%d for %d)", + argc, m); + } + return 0; + } + else { + VALUE * const dst = argv; + int opt_pc = 0; + + /* mandatory */ + if (argc < (m + iseq->arg_post_len)) { /* check with post arg */ + rb_raise(rb_eArgError, "wrong number of arguments (%d for %d)", + argc, m + iseq->arg_post_len); + } + + argv += m; + argc -= m; + + /* post arguments */ + if (iseq->arg_post_len) { + int i; + + if (!(orig_argc < iseq->arg_post_start)) { + VALUE *new_argv = ALLOCA_N(VALUE, argc); + MEMCPY(new_argv, argv, VALUE, argc); + argv = new_argv; + } + + for (i=0; i<iseq->arg_post_len; i++) { + dst[iseq->arg_post_start + iseq->arg_post_len - (i + 1)] = argv[argc - 1]; + argc = argc - 1; + } + } + + /* opt arguments */ + if (iseq->arg_opts) { + const int opts = iseq->arg_opts - 1 /* no opt */; + + if (iseq->arg_rest == -1 && argc > opts) { + rb_raise(rb_eArgError, "wrong number of arguments (%d for %d)", orig_argc, m + opts); + } + + if (argc > opts) { + argc -= opts; + argv += opts; + opt_pc = iseq->arg_opt_tbl[opts]; /* no opt */ + } + else { + opt_pc = iseq->arg_opt_tbl[argc]; + argc = 0; + } + } + + /* rest arguments */ + if (iseq->arg_rest != -1) { + dst[iseq->arg_rest] = rb_ary_new4(argc, argv); + } + + /* block arguments */ + if (iseq->arg_block != -1) { + VALUE blockval = Qnil; + rb_block_t * const blockptr = *block; + + if (blockptr) { + /* make Proc object */ + if (blockptr->proc == 0) { + rb_proc_t *proc; + + th->mark_stack_len = orig_argc; /* for GC */ + blockval = th_make_proc(th, th->cfp, blockptr); + th->mark_stack_len = 0; + + GetProcPtr(blockval, proc); + *block = &proc->block; + } + else { + blockval = blockptr->proc; + } + } + + dst[iseq->arg_block] = blockval; /* Proc or nil */ + } + + return opt_pc; + } +} /* Env */ |