summaryrefslogtreecommitdiffhomepage
path: root/src/vm.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/vm.c')
-rw-r--r--src/vm.c102
1 files changed, 101 insertions, 1 deletions
diff --git a/src/vm.c b/src/vm.c
index 503d2c929..649596713 100644
--- a/src/vm.c
+++ b/src/vm.c
@@ -507,6 +507,98 @@ mrb_f_send(mrb_state *mrb, mrb_value self)
return self;
}
+static mrb_value
+eval_under(mrb_state *mrb, mrb_value self, mrb_value blk, struct RClass *c)
+{
+ struct RProc *p;
+ mrb_callinfo *ci;
+
+ ci = mrb->c->ci;
+ if (ci->acc == CI_ACC_DIRECT) {
+ return mrb_yield_with_class(mrb, blk, 0, 0, self, c);
+ }
+ ci->target_class = c;
+ p = mrb_proc_ptr(blk);
+ ci->proc = p;
+ if (MRB_PROC_CFUNC_P(p)) {
+ return p->body.func(mrb, self);
+ }
+ ci->nregs = p->body.irep->nregs;
+ ci = cipush(mrb);
+ ci->target_class = 0;
+ ci->pc = p->body.irep->iseq;
+ ci->stackent = mrb->c->stack;
+ ci->acc = 0;
+
+ return self;
+}
+
+/* 15.2.2.4.35 */
+/*
+ * call-seq:
+ * mod.class_eval {| | block } -> obj
+ * mod.module_eval {| | block } -> obj
+ *
+ * Evaluates block in the context of _mod_. This can
+ * be used to add methods to a class. <code>module_eval</code> returns
+ * the result of evaluating its argument.
+ */
+mrb_value
+mrb_mod_module_eval(mrb_state *mrb, mrb_value mod)
+{
+ mrb_value a, b;
+
+ if (mrb_get_args(mrb, "|S&", &a, &b) == 1) {
+ mrb_raise(mrb, E_NOTIMP_ERROR, "module_eval/class_eval with string not implemented");
+ }
+ return eval_under(mrb, mod, b, mrb_class_ptr(mod));
+}
+
+/* 15.3.1.3.18 */
+/*
+ * call-seq:
+ * obj.instance_eval {| | block } -> obj
+ *
+ * Evaluates the given block,within the context of the receiver (_obj_).
+ * In order to set the context, the variable +self+ is set to _obj_ while
+ * the code is executing, giving the code access to _obj_'s
+ * instance variables. In the version of <code>instance_eval</code>
+ * that takes a +String+, the optional second and third
+ * parameters supply a filename and starting line number that are used
+ * when reporting compilation errors.
+ *
+ * class KlassWithSecret
+ * def initialize
+ * @secret = 99
+ * end
+ * end
+ * k = KlassWithSecret.new
+ * k.instance_eval { @secret } #=> 99
+ */
+mrb_value
+mrb_obj_instance_eval(mrb_state *mrb, mrb_value self)
+{
+ mrb_value a, b;
+ mrb_value cv;
+ struct RClass *c;
+
+ if (mrb_get_args(mrb, "|S&", &a, &b) == 1) {
+ mrb_raise(mrb, E_NOTIMP_ERROR, "instance_eval with string not implemented");
+ }
+ switch (mrb_type(self)) {
+ case MRB_TT_SYMBOL:
+ case MRB_TT_FIXNUM:
+ case MRB_TT_FLOAT:
+ c = 0;
+ break;
+ default:
+ cv = mrb_singleton_class(mrb, self);
+ c = mrb_class_ptr(cv);
+ break;
+ }
+ return eval_under(mrb, self, b, c);
+}
+
mrb_value
mrb_yield_with_class(mrb_state *mrb, mrb_value b, mrb_int argc, const mrb_value *argv, mrb_value self, struct RClass *c)
{
@@ -1481,7 +1573,15 @@ RETRY_TRY_BLOCK:
mrb->c = c->prev;
c->prev = NULL;
}
- ci = mrb->c->ci = mrb->c->cibase + proc->env->cioff + 1;
+ ci = mrb->c->ci;
+ mrb->c->ci = mrb->c->cibase + proc->env->cioff + 1;
+ while (ci > mrb->c->ci) {
+ if (ci[-1].acc == CI_ACC_SKIP) {
+ mrb->c->ci = ci;
+ break;
+ }
+ ci--;
+ }
break;
default:
/* cannot happen */