summaryrefslogtreecommitdiff
path: root/vm.c
diff options
context:
space:
mode:
authorko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2007-06-24 07:29:21 +0000
committerko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2007-06-24 07:29:21 +0000
commit68e02f2c2cc98e6ab736b3122aafe7a2398642f6 (patch)
tree2167a1299cd58748a883b72de1ba8de0b4128df6 /vm.c
parenta5c9bf7d63bff7772d7a3b392e9d5ebe6a0bf479 (diff)
* 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.c97
1 files changed, 97 insertions, 0 deletions
diff --git a/vm.c b/vm.c
index 6ad62d2fa9..376b5efc15 100644
--- a/vm.c
+++ b/vm.c
@@ -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 */