summaryrefslogtreecommitdiffhomepage
path: root/src/class.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/class.c')
-rw-r--r--src/class.c109
1 files changed, 67 insertions, 42 deletions
diff --git a/src/class.c b/src/class.c
index fdf63794b..1403ed48e 100644
--- a/src/class.c
+++ b/src/class.c
@@ -812,9 +812,9 @@ ensure_class_type(mrb_state *mrb, mrb_value val)
MRB_API mrb_int
mrb_get_argc(mrb_state *mrb)
{
- mrb_int argc = mrb->c->ci->argc;
+ mrb_int argc = mrb->c->ci->n;
- if (argc < 0) {
+ if (argc == 15) {
struct RArray *a = mrb_ary_ptr(mrb->c->ci->stack[1]);
argc = ARY_LEN(a);
@@ -825,9 +825,9 @@ mrb_get_argc(mrb_state *mrb)
MRB_API const mrb_value*
mrb_get_argv(mrb_state *mrb)
{
- mrb_int argc = mrb->c->ci->argc;
+ mrb_int argc = mrb->c->ci->n;
mrb_value *array_argv = mrb->c->ci->stack + 1;
- if (argc < 0) {
+ if (argc == 15) {
struct RArray *a = mrb_ary_ptr(*array_argv);
array_argv = ARY_PTR(a);
@@ -838,33 +838,37 @@ mrb_get_argv(mrb_state *mrb)
MRB_API mrb_value
mrb_get_arg1(mrb_state *mrb)
{
- mrb_int argc = mrb->c->ci->argc;
- mrb_value *array_argv = mrb->c->ci->stack + 1;
- if (argc < 0) {
+ mrb_callinfo *ci = mrb->c->ci;
+ mrb_int argc = ci->n;
+ mrb_value *array_argv = ci->stack + 1;
+ if (argc == 15) {
struct RArray *a = mrb_ary_ptr(*array_argv);
argc = ARY_LEN(a);
array_argv = ARY_PTR(a);
}
+ if (argc == 0 && ci->nk == 15) {
+ mrb_int n = ci->n;
+ if (n == 15) n = 1;
+ return ci->stack[n+1]; /* kwhash next to positional arguments */
+ }
if (argc != 1) {
mrb_argnum_error(mrb, argc, 1, 1);
}
return array_argv[0];
}
+mrb_int mrb_ci_bidx(mrb_callinfo *ci);
+
MRB_API mrb_bool
mrb_block_given_p(mrb_state *mrb)
{
- const mrb_callinfo *ci = mrb->c->ci;
- int argc = ci->argc;
- int idx = (argc < 0) ? 2 : argc + 1;
- mrb_value b = ci->stack[idx];
+ mrb_callinfo *ci = mrb->c->ci;
+ mrb_value b = ci->stack[mrb_ci_bidx(ci)];
return !mrb_nil_p(b);
}
-void mrb_hash_check_kdict(mrb_state *mrb, mrb_value self);
-
/*
retrieve arguments from mrb_state.
@@ -911,21 +915,17 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
char c;
int i = 0;
va_list ap;
- int argc = mrb->c->ci->argc;
- const mrb_value *argv = mrb->c->ci->stack+1;
- mrb_bool argv_on_stack = argc >= 0;
+ mrb_callinfo *ci = mrb->c->ci;
+ int argc = ci->n;
+ const mrb_value *argv = ci->stack+1;
+ mrb_bool argv_on_stack;
mrb_bool opt = FALSE;
mrb_bool opt_skip = TRUE;
const mrb_value *pickarg = NULL; /* arguments currently being processed */
- mrb_value kdict;
+ mrb_value kdict = mrb_nil_value();
mrb_bool reqkarg = FALSE;
int argc_min = 0, argc_max = 0;
- if (!argv_on_stack) {
- struct RArray *a = mrb_ary_ptr(*argv);
- argv = ARY_PTR(a);
- argc = ARY_LEN(a);
- }
va_start(ap, format);
while ((c = *fmt++)) {
@@ -955,12 +955,41 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
}
check_exit:
- if (reqkarg && argc > argc_min && mrb_hash_p(kdict = argv[argc - 1])) {
- mrb_hash_check_kdict(mrb, kdict);
- argc--;
+ if (!reqkarg && ci->nk > 0) {
+ mrb_assert(ci->nk == 15);
+ kdict = ci->stack[mrb_ci_bidx(ci)-1];
+ if (mrb_hash_p(kdict) && mrb_hash_size(mrb, kdict) > 0) {
+ if (argc < 14) {
+ ci->n++;
+ argc++; /* include kdict in normal arguments */
+ }
+ else {
+ /* 14+1 == 15 so pack first */
+ if (argc == 14) {
+ /* pack arguments and kdict */
+ ci->stack[1] = mrb_ary_new_from_values(mrb, argc+1, &ci->stack[1]);
+ argc = ci->n = 15;
+ }
+ else {
+ /* push kdict to packed arguments */
+ mrb_ary_push(mrb, ci->stack[1], kdict);
+ }
+ ci->stack[2] = ci->stack[mrb_ci_bidx(ci)];
+ }
+ ci->nk = 0;
+ }
}
- else {
- kdict = mrb_nil_value();
+ if (reqkarg && ci->nk > 0) {
+ kdict = ci->stack[mrb_ci_bidx(ci)-1];
+ mrb_assert(ci->nk == 15);
+ mrb_assert(mrb_hash_p(kdict));
+ }
+
+ argv_on_stack = argc < 15;
+ if (!argv_on_stack) {
+ struct RArray *a = mrb_ary_ptr(*argv);
+ argv = ARY_PTR(a);
+ argc = ARY_LEN(a);
}
opt = FALSE;
@@ -989,7 +1018,7 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
case '|': case '*': case '&': case '?': case ':':
if (needmodify) {
bad_needmodify:
- mrb_raisef(mrb, E_ARGUMENT_ERROR, "wrong `%c+` modified specifer`", c);
+ mrb_raisef(mrb, E_ARGUMENT_ERROR, "wrong `%c+` modified specifier`", c);
}
break;
default:
@@ -1200,12 +1229,7 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
mrb_value *p, *bp;
p = va_arg(ap, mrb_value*);
- if (mrb->c->ci->argc < 0) {
- bp = mrb->c->ci->stack + 2;
- }
- else {
- bp = mrb->c->ci->stack + mrb->c->ci->argc + 1;
- }
+ bp = ci->stack + mrb_ci_bidx(ci);
if (altmode && mrb_nil_p(*bp)) {
mrb_raise(mrb, E_ARGUMENT_ERROR, "no block given");
}
@@ -2812,14 +2836,15 @@ inspect_main(mrb_state *mrb, mrb_value mod)
}
static const mrb_code new_iseq[] = {
- OP_ENTER, 0x0, 0x10, 0x1, /* OP_ENTER 0:0:1:0:0:0:1 */
- OP_LOADSELF, 0x3, /* OP_LOADSELF R3 */
- OP_SEND, 0x3, 0x0, 0x0, /* OP_SEND R3 :allocate 0 */
- OP_MOVE, 0x0, 0x3, /* OP_MOVE R0 R3 */
- OP_MOVE, 0x4, 0x1, /* OP_MOVE R4 R1 */
- OP_MOVE, 0x5, 0x2, /* OP_MOVE R5 R2 */
- OP_SENDVB, 0x3, 0x1, /* OP_SENDVB R3 :initialize */
- OP_RETURN, 0x0 /* OP_RETURN R0 */
+ OP_ENTER, 0x0, 0x10, 0x3, // OP_ENTER 0:0:1:0:0:1:1
+ OP_LOADSELF, 4, // OP_LOADSELF R4
+ OP_SEND, 4, 0, 0, // OP_SEND R4 :allocate n=0
+ OP_MOVE, 0, 4, // OP_MOVE R0 R4
+ OP_MOVE, 5, 1, // OP_MOVE R5 R1 (*)
+ OP_MOVE, 6, 2, // OP_MOVE R6 R2 (**)
+ OP_MOVE, 7, 3, // OP_MOVE R7 R3
+ OP_SENDB, 4, 1, 255, // OP_SENDB R4 :initialize n=*|nk=*
+ OP_RETURN, 0 // OP_RETURN R0
};
MRB_PRESYM_DEFINE_VAR_AND_INITER(new_syms, 2, MRB_SYM(allocate), MRB_SYM(initialize))