summaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorYukihiro "Matz" Matsumoto <[email protected]>2017-08-01 11:39:18 +0900
committerYukihiro "Matz" Matsumoto <[email protected]>2017-08-01 15:37:21 +0900
commit9e10afe1d0ee1fb751182e42044e891b4b13f9a4 (patch)
tree880a62052f924ad037dedaca434e474f820a91ed /src
parent16aafdd8660dc301b49254e7ccaa887ab3a458de (diff)
downloadmruby-9e10afe1d0ee1fb751182e42044e891b4b13f9a4.tar.gz
mruby-9e10afe1d0ee1fb751182e42044e891b4b13f9a4.zip
Implements `Module::nesting' (15.2.2.3.2); ref #600, #3200
Diffstat (limited to 'src')
-rw-r--r--src/class.c3
-rw-r--r--src/gc.c3
-rw-r--r--src/vm.c35
3 files changed, 37 insertions, 4 deletions
diff --git a/src/class.c b/src/class.c
index 57f64dcc5..54754092e 100644
--- a/src/class.c
+++ b/src/class.c
@@ -2314,6 +2314,8 @@ mrb_mod_module_function(mrb_state *mrb, mrb_value mod)
mrb_value mrb_obj_id_m(mrb_state *mrb, mrb_value self);
/* implementation of instance_eval */
mrb_value mrb_obj_instance_eval(mrb_state*, mrb_value);
+/* implementation of Module.nesting */
+mrb_value mrb_mod_s_nesting(mrb_state*, mrb_value);
void
mrb_init_class(mrb_state *mrb)
@@ -2407,6 +2409,7 @@ mrb_init_class(mrb_state *mrb)
mrb_define_method(mrb, mod, "class_variables", mrb_mod_class_variables, MRB_ARGS_NONE()); /* 15.2.2.4.19 */
mrb_define_method(mrb, mod, "===", mrb_mod_eqq, MRB_ARGS_REQ(1));
mrb_define_class_method(mrb, mod, "constants", mrb_mod_s_constants, MRB_ARGS_ANY()); /* 15.2.2.3.1 */
+ mrb_define_class_method(mrb, mod, "nesting", mrb_mod_s_nesting, MRB_ARGS_REQ(0)); /* 15.2.2.3.2 */
mrb_undef_method(mrb, cls, "append_features");
mrb_undef_method(mrb, cls, "extend_object");
diff --git a/src/gc.c b/src/gc.c
index 8cc8feb08..cd885f7e8 100644
--- a/src/gc.c
+++ b/src/gc.c
@@ -647,6 +647,9 @@ gc_mark_children(mrb_state *mrb, mrb_gc *gc, struct RBasic *obj)
mrb_gc_mark(mrb, (struct RBasic*)p->env);
mrb_gc_mark(mrb, (struct RBasic*)p->target_class);
+ if (!MRB_PROC_CFUNC_P(p)) {
+ mrb_gc_mark(mrb, (struct RBasic*)p->body.irep->outer);
+ }
}
break;
diff --git a/src/vm.c b/src/vm.c
index 45f9bf967..152a28651 100644
--- a/src/vm.c
+++ b/src/vm.c
@@ -778,6 +778,25 @@ mrb_yield_cont(mrb_state *mrb, mrb_value b, mrb_value self, mrb_int argc, const
return mrb_exec_irep(mrb, self, p);
}
+mrb_value
+mrb_mod_s_nesting(mrb_state *mrb, mrb_value mod)
+{
+ struct RProc *proc;
+ mrb_value ary;
+
+ mrb_get_args(mrb, "");
+ ary = mrb_ary_new(mrb);
+ proc = mrb->c->ci[-1].proc; /* callee proc */
+ while (proc) {
+ mrb_assert(!MRB_PROC_CFUNC_P(proc));
+ if (MRB_PROC_CLASS_P(proc) && proc->target_class) {
+ mrb_ary_push(mrb, ary, mrb_obj_value(proc->target_class));
+ }
+ proc = proc->body.irep->outer;
+ }
+ return ary;
+}
+
static struct RBreak*
break_new(mrb_state *mrb, struct RProc *p, mrb_value val)
{
@@ -2701,16 +2720,20 @@ RETRY_TRY_BLOCK:
CASE(OP_LAMBDA) {
/* A b c R(A) := lambda(SEQ[b],c) (b:c = 14:2) */
struct RProc *p;
+ int a = GETARG_A(i);
+ int b = GETARG_b(i);
int c = GETARG_c(i);
+ mrb_irep *nirep = irep->reps[b];
+ nirep->outer = mrb->c->ci->proc;
if (c & OP_L_CAPTURE) {
- p = mrb_closure_new(mrb, irep->reps[GETARG_b(i)]);
+ p = mrb_closure_new(mrb, nirep);
}
else {
- p = mrb_proc_new(mrb, irep->reps[GETARG_b(i)]);
+ p = mrb_proc_new(mrb, nirep);
}
if (c & OP_L_STRICT) p->flags |= MRB_PROC_STRICT;
- regs[GETARG_A(i)] = mrb_obj_value(p);
+ regs[a] = mrb_obj_value(p);
mrb_gc_arena_restore(mrb, ai);
NEXT;
}
@@ -2765,13 +2788,17 @@ RETRY_TRY_BLOCK:
CASE(OP_EXEC) {
/* A Bx R(A) := blockexec(R(A),SEQ[Bx]) */
int a = GETARG_A(i);
+ int bx = GETARG_Bx(i);
mrb_callinfo *ci;
mrb_value recv = regs[a];
struct RProc *p;
+ mrb_irep *nirep = irep->reps[bx];
+ nirep->outer = mrb->c->ci->proc;
/* prepare closure */
- p = mrb_closure_new(mrb, irep->reps[GETARG_Bx(i)]);
+ p = mrb_closure_new(mrb, nirep);
p->c = NULL;
+ p->flags |= MRB_PROC_CLASS;
/* prepare stack */
ci = cipush(mrb);