diff options
Diffstat (limited to 'src/kernel.c')
| -rw-r--r-- | src/kernel.c | 43 |
1 files changed, 31 insertions, 12 deletions
diff --git a/src/kernel.c b/src/kernel.c index 9fdd939e3..4a20e18c1 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -134,33 +134,52 @@ mrb_obj_id_m(mrb_state *mrb, mrb_value self) static mrb_value mrb_f_block_given_p_m(mrb_state *mrb, mrb_value self) { - mrb_callinfo *ci = mrb->c->ci; + mrb_callinfo *ci = &mrb->c->ci[-1]; + mrb_callinfo *cibase = mrb->c->cibase; mrb_value *bp; struct RProc *p; - bp = ci->stackent + 1; - ci--; - if (ci <= mrb->c->cibase) { + if (ci <= cibase) { + /* toplevel does not have block */ return mrb_false_value(); } - /* block_given? called within block; check upper scope */ p = ci->proc; + /* search method/class/module proc */ while (p) { if (MRB_PROC_SCOPE_P(p)) break; p = p->upper; } - /* top-level does not have block slot (always false) */ if (p == NULL) return mrb_false_value(); - if (MRB_PROC_ENV_P(p)) { - struct REnv *e = MRB_PROC_ENV(p); + /* search ci corresponding to proc */ + while (cibase < ci) { + if (ci->proc == p) break; + ci--; + } + if (ci == cibase) { + return mrb_false_value(); + } + else if (ci->env) { + struct REnv *e = ci->env; + int bidx; + /* top-level does not have block slot (always false) */ if (e->stack == mrb->c->stbase) return mrb_false_value(); /* use saved block arg position */ - bp = &e->stack[MRB_ENV_BIDX(e)]; + bidx = MRB_ENV_BIDX(e); + /* bidx may be useless (e.g. define_method) */ + if (bidx >= MRB_ENV_STACK_LEN(e)) + return mrb_false_value(); + bp = &e->stack[bidx]; } - if (ci && ci->argc > 0) { - bp += ci->argc; + else { + bp = ci[1].stackent+1; + if (ci->argc >= 0) { + bp += ci->argc; + } + else { + bp++; + } } if (mrb_nil_p(*bp)) return mrb_false_value(); @@ -1183,7 +1202,7 @@ mrb_local_variables(mrb_state *mrb, mrb_value self) } if (!MRB_PROC_ENV_P(proc)) break; proc = proc->upper; - // if (MRB_PROC_SCOPE_P(proc)) break; + //if (MRB_PROC_SCOPE_P(proc)) break; if (!proc->c) break; } |
