diff options
Diffstat (limited to 'src/vm.c')
| -rw-r--r-- | src/vm.c | 47 |
1 files changed, 28 insertions, 19 deletions
@@ -1136,6 +1136,13 @@ check_target_class(mrb_state *mrb) return TRUE; } +mrb_value +get_send_args(mrb_state *mrb, mrb_int argc, mrb_value *regs) +{ + if (argc < 0) return regs[0]; + return mrb_ary_new_from_values(mrb, argc, regs); +} + mrb_value mrb_obj_missing(mrb_state *mrb, mrb_value mod); void mrb_hash_check_kdict(mrb_state *mrb, mrb_value self); @@ -1552,11 +1559,18 @@ RETRY_TRY_BLOCK: m = mrb_method_search_vm(mrb, &cls, mid); if (MRB_METHOD_UNDEF_P(m)) { mrb_sym missing = MRB_SYM(method_missing); - m = mrb_method_search_vm(mrb, &cls, missing); - if (MRB_METHOD_UNDEF_P(m) || (missing == mrb->c->ci->mid && mrb_obj_eq(mrb, regs[0], recv))) { - mrb_value args = (argc < 0) ? regs[a+1] : mrb_ary_new_from_values(mrb, c, regs+a+1); + mrb_value args; + + if (mrb_func_basic_p(mrb, recv, missing, mrb_obj_missing)) { + method_missing: + args = get_send_args(mrb, argc, regs+a+1); mrb_method_missing(mrb, mid, recv, args); } + if (mid != missing) { + cls = mrb_class(mrb, recv); + } + m = mrb_method_search_vm(mrb, &cls, missing); + if (MRB_METHOD_UNDEF_P(m)) goto method_missing; /* just in case */ if (argc >= 0) { if (a+2 >= irep->nregs) { mrb_stack_extend(mrb, a+3); @@ -1614,7 +1628,6 @@ RETRY_TRY_BLOCK: /* pop stackpos */ ci = cipop(mrb); pc = ci->pc; - JUMP; } else { /* setup environment for calling method */ @@ -1624,9 +1637,9 @@ RETRY_TRY_BLOCK: syms = irep->syms; mrb_stack_extend(mrb, (argc < 0 && irep->nregs < 3) ? 3 : irep->nregs); pc = irep->iseq; - JUMP; } } + JUMP; CASE(OP_CALL, Z) { mrb_callinfo *ci; @@ -1712,13 +1725,12 @@ RETRY_TRY_BLOCK: else if (target_class->tt == MRB_TT_MODULE) { target_class = mrb_vm_ci_target_class(ci); if (target_class->tt != MRB_TT_ICLASS) { - mrb_value exc = mrb_exc_new_lit(mrb, E_RUNTIME_ERROR, "superclass info lost [mruby limitations]"); - mrb_exc_set(mrb, exc); - goto L_RAISE; + goto super_typeerror; } } recv = regs[0]; if (!mrb_obj_is_kind_of(mrb, recv, target_class)) { + super_typeerror: ; mrb_value exc = mrb_exc_new_lit(mrb, E_TYPE_ERROR, "self has wrong type to call super in this context"); mrb_exc_set(mrb, exc); @@ -1736,20 +1748,18 @@ RETRY_TRY_BLOCK: m = mrb_method_search_vm(mrb, &cls, mid); if (MRB_METHOD_UNDEF_P(m)) { mrb_sym missing = MRB_SYM(method_missing); + mrb_value args; if (mrb_func_basic_p(mrb, recv, missing, mrb_obj_missing)) { - mrb_value args = (argc < 0) ? regs[a+1] : mrb_ary_new_from_values(mrb, b, regs+a+1); + super_missing: + args = get_send_args(mrb, argc, regs+a+1); mrb_no_method_error(mrb, mid, args, "no superclass method '%n'", mid); } if (mid != missing) { cls = mrb_class(mrb, recv); } m = mrb_method_search_vm(mrb, &cls, missing); - if (MRB_METHOD_UNDEF_P(m)) { /* just in case */ - mrb_value args = (argc < 0) ? regs[a+1] : mrb_ary_new_from_values(mrb, b, regs+a+1); - mrb_method_missing(mrb, missing, recv, args); - } - mid = missing; + if (MRB_METHOD_UNDEF_P(m)) goto super_missing; /* just in case */ if (argc >= 0) { if (a+2 >= irep->nregs) { mrb_stack_extend(mrb, a+3); @@ -1758,7 +1768,8 @@ RETRY_TRY_BLOCK: regs[a+2] = blk; argc = -1; } - mrb_ary_unshift(mrb, regs[a+1], mrb_symbol_value(ci->mid)); + mrb_ary_unshift(mrb, regs[a+1], mrb_symbol_value(mid)); + mid = missing; } /* push callinfo */ @@ -2150,7 +2161,7 @@ RETRY_TRY_BLOCK: } /* check jump destination */ while (cibase <= ci && ci->proc != dst) { - if (ci->acc < 0) { /* jump cross C boudary */ + if (ci->acc < 0) { /* jump cross C boundary */ localjump_error(mrb, LOCALJUMP_ERROR_RETURN); goto L_RAISE; } @@ -2440,9 +2451,7 @@ RETRY_TRY_BLOCK: CASE(OP_DIV, B) { #ifndef MRB_NO_FLOAT mrb_float x, y, f; - mrb_float mrb_div_flo(mrb_float x, mrb_float y); #endif - mrb_int mrb_div_int(mrb_state *mrb, mrb_int x, mrb_int y); /* need to check if op is overridden */ switch (TYPES2(mrb_type(regs[a]),mrb_type(regs[a+1]))) { @@ -2475,7 +2484,7 @@ RETRY_TRY_BLOCK: } #ifndef MRB_NO_FLOAT - f = mrb_div_flo(x, y); + f = mrb_div_float(x, y); SET_FLOAT_VALUE(mrb, regs[a], f); #endif NEXT; |
