Index: env.h
===================================================================
RCS file: /src/ruby/env.h,v
retrieving revision 1.22
diff -u -p -r1.22 env.h
--- env.h	17 Feb 2006 16:08:08 -0000	1.22
+++ env.h	30 Jun 2006 03:43:06 -0000
@@ -25,6 +25,7 @@ RUBY_EXTERN struct FRAME {
     struct BLOCK *block;
     int flags;
     unsigned long uniq;
+    struct RVarmap *dyna_vars;
 } *ruby_frame;
 
 void rb_gc_mark_frame(struct FRAME *);
@@ -36,13 +37,15 @@ RUBY_EXTERN struct SCOPE {
     struct RBasic super;
     ID *local_tbl;
     VALUE *local_vars;
-    int flags;
+    struct SCOPE *prev;
 } *ruby_scope;
 
-#define SCOPE_ALLOCA  0
-#define SCOPE_MALLOC  1
-#define SCOPE_NOSTACK 2
-#define SCOPE_DONT_RECYCLE 4
+#define SCOPE_ALLOCA  FL_USER1
+#define SCOPE_MALLOC  FL_USER2
+#define SCOPE_NOSTACK FL_USER3
+#define SCOPE_DONT_RECYCLE FL_USER4
+
+#define SCOPE_FLAGS(scope) (RBASIC(scope)->flags)
 
 RUBY_EXTERN int ruby_in_eval;
 VALUE ruby_current_class_object(void);
Index: eval.c
===================================================================
RCS file: /src/ruby/eval.c,v
retrieving revision 1.910
diff -u -p -r1.910 eval.c
--- eval.c	28 Jun 2006 04:51:27 -0000	1.910
+++ eval.c	30 Jun 2006 03:43:06 -0000
@@ -761,6 +761,7 @@ static unsigned long frame_unique = 1;
     _frame.callee = 0;			\
     _frame.this_func = 0;		\
     _frame.this_class = 0;		\
+    _frame.dyna_vars = ruby_dyna_vars;	\
     ruby_frame = &_frame
 
 #define POP_FRAME()  			\
@@ -799,7 +800,7 @@ struct RVarmap *ruby_dyna_vars;
     ruby_dyna_vars = 0
 
 #define POP_VARS() \
-    if (_old && (ruby_scope->flags & SCOPE_DONT_RECYCLE)) {\
+    if (_old && (SCOPE_FLAGS(ruby_scope) & SCOPE_DONT_RECYCLE)) {\
 	if (RBASIC(_old)->flags) /* unless it's already recycled */ \
 	    FL_SET(_old, DVAR_DONT_RECYCLE); \
     }\
@@ -993,8 +994,7 @@ static NODE *top_cref;
     OBJSETUP(_scope, 0, T_SCOPE);	\
     _scope->local_tbl = 0;		\
     _scope->local_vars = 0;		\
-    _scope->flags = 0;			\
-    _old = ruby_scope;			\
+    _scope->prev = _old = ruby_scope;	\
     ruby_scope = _scope;		\
     vis_mode = VIS_PUBLIC
 
@@ -1004,18 +1004,19 @@ static rb_thread_t main_thread;
 static void scope_dup(struct SCOPE *);
 
 #define POP_SCOPE() 			\
-    if (ruby_scope->flags & SCOPE_DONT_RECYCLE) {\
+    if (SCOPE_FLAGS(ruby_scope) & SCOPE_DONT_RECYCLE) {\
 	if (_old) scope_dup(_old);	\
     }					\
-    if (!(ruby_scope->flags & SCOPE_MALLOC)) {\
+    if (!(SCOPE_FLAGS(ruby_scope) & SCOPE_MALLOC)) {\
 	ruby_scope->local_vars = 0;	\
 	ruby_scope->local_tbl  = 0;	\
-	if (!(ruby_scope->flags & SCOPE_DONT_RECYCLE) && \
+	if (!(SCOPE_FLAGS(ruby_scope) & SCOPE_DONT_RECYCLE) && \
 	    ruby_scope != top_scope) {	\
 	    rb_gc_force_recycle((VALUE)ruby_scope);\
 	}				\
     }					\
-    ruby_scope->flags |= SCOPE_NOSTACK;	\
+    if (SCOPE_FLAGS(ruby_scope) != 0)	\
+    	SCOPE_FLAGS(ruby_scope) |= SCOPE_NOSTACK;	\
     ruby_scope = _old;			\
     vis_mode = _vmode;			\
 } while (0)
@@ -1392,7 +1393,7 @@ ruby_init(void)
     }
     POP_SCOPE();
     ruby_scope = top_scope;
-    top_scope->flags &= ~SCOPE_NOSTACK;
+    SCOPE_FLAGS(top_scope) &= ~SCOPE_NOSTACK;
     ruby_running = 1;
 }
 
@@ -1803,7 +1804,7 @@ rb_eval_cmd(VALUE cmd, VALUE arg, int le
     if ((state = EXEC_TAG()) == 0) {
 	val = eval(ruby_top_self, cmd, Qnil, 0, 0);
     }
-    if (ruby_scope->flags & SCOPE_DONT_RECYCLE)
+    if (SCOPE_FLAGS(ruby_scope) & SCOPE_DONT_RECYCLE)
 	scope_dup(saved_scope);
     ruby_scope = saved_scope;
     ruby_safe_level = safe;
@@ -4854,7 +4855,7 @@ rb_yield_0(VALUE val, VALUE self, VALUE 
     ruby_frame = ruby_frame->prev;
     ruby_cref = (NODE*)old_cref;
     ruby_wrapper = old_wrapper;
-    if (ruby_scope->flags & SCOPE_DONT_RECYCLE)
+    if (SCOPE_FLAGS(ruby_scope) & SCOPE_DONT_RECYCLE)
 	scope_dup(old_scope);
     ruby_scope = old_scope;
     vis_mode = old_vmode;
@@ -6265,7 +6266,7 @@ eval(VALUE self, VALUE src, VALUE scope,
     POP_TAG();
     ruby_in_eval--;
     if (!NIL_P(scope)) {
-	int dont_recycle = ruby_scope->flags & SCOPE_DONT_RECYCLE;
+	int dont_recycle = SCOPE_FLAGS(ruby_scope) & SCOPE_DONT_RECYCLE;
 
 	ruby_wrapper = old_wrapper;
 	ruby_cref  = (NODE*)old_cref;
@@ -6695,7 +6696,7 @@ rb_load(VALUE fname, int wrap)
     ruby_current_node = last_node;
     ruby_sourcefile = 0;
     ruby_set_current_source();
-    if (ruby_scope->flags == SCOPE_ALLOCA && ruby_cbase == rb_cObject) {
+    if (SCOPE_FLAGS(ruby_scope) == SCOPE_ALLOCA && ruby_cbase == rb_cObject) {
 	if (ruby_scope->local_tbl) /* toplevel was empty */
 	    free(ruby_scope->local_tbl);
     }
@@ -7999,8 +8000,8 @@ scope_dup(struct SCOPE *scope)
     volatile ID *tbl;
     VALUE *vars;
 
-    scope->flags |= SCOPE_DONT_RECYCLE;
-    if (scope->flags & SCOPE_MALLOC) return;
+    SCOPE_FLAGS(scope) |= SCOPE_DONT_RECYCLE;
+    if (SCOPE_FLAGS(scope) & SCOPE_MALLOC) return;
 
     if (scope->local_tbl) {
 	tbl = scope->local_tbl;
@@ -8008,7 +8009,7 @@ scope_dup(struct SCOPE *scope)
 	*vars++ = scope->local_vars[-1];
 	MEMCPY(vars, scope->local_vars, VALUE, tbl[0]);
 	scope->local_vars = vars;
-	scope->flags |= SCOPE_MALLOC;
+	SCOPE_FLAGS(scope) |= SCOPE_MALLOC;
     }
 }
 
@@ -8214,6 +8215,51 @@ bind_eval(int argc, VALUE *argv, VALUE b
     return rb_f_eval(argc+1, args, data->self);
 }
 
+/*
+ *  call-seq:
+ *     Binding.of_caller -> a_binding
+ *     Binding.of_caller {|bind| block } -> an_object
+ *  
+ *  Returns a +Binding+ object of a caller.
+ *     
+ *     def print_x
+ *       eval("p x", Binding.of_caller)
+ *     end
+ *     x = 1
+ *     print_x   #=> 1
+ */
+
+static VALUE
+bind_s_of_caller(VALUE self)
+{
+    struct SCOPE *old_scope;
+    struct RVarmap *old_dyna_vars;
+    struct FRAME *old_frame;
+    VALUE bind;
+
+    if (ruby_frame->prev == 0 || ruby_frame->prev->prev == 0 ||
+	ruby_scope->prev == 0) {
+	rb_raise(rb_eRuntimeError, "called outside of method");
+    }
+
+    old_scope = ruby_scope;
+    old_dyna_vars = ruby_dyna_vars;
+    old_frame = ruby_frame;
+    ruby_scope = ruby_scope->prev;
+    ruby_dyna_vars = ruby_frame->prev->dyna_vars;
+    ruby_frame = ruby_frame->prev->prev;
+    bind = rb_f_binding(ruby_frame->self);
+    ruby_scope = old_scope;
+    ruby_dyna_vars = old_dyna_vars;
+    ruby_frame = old_frame;
+    if (rb_block_given_p()) {
+	return rb_yield(bind);
+    }
+    else {
+	return bind;
+    }
+}
+
 #define PROC_TSHIFT (FL_USHIFT+1)
 #define PROC_TMASK  (FL_USER1|FL_USER2|FL_USER3)
 #define PROC_TMAX   (PROC_TMASK >> PROC_TSHIFT)
@@ -8351,7 +8397,7 @@ proc_lambda(void)
 static int
 block_orphan(struct BLOCK *data)
 {
-    if (data->scope->flags & SCOPE_NOSTACK) {
+    if (SCOPE_FLAGS(data->scope) & SCOPE_NOSTACK) {
 	return 1;
     }
     if (data->orig_thread != rb_thread_current()) {
@@ -9608,6 +9654,7 @@ Init_Binding(void)
     rb_define_method(rb_cBinding, "clone", proc_clone, 0);
     rb_define_method(rb_cBinding, "dup", proc_dup, 0);
     rb_define_method(rb_cBinding, "eval", bind_eval, -1);
+    rb_define_singleton_method(rb_cBinding, "of_caller", bind_s_of_caller, 0);
     rb_define_global_function("binding", rb_f_binding, 0);
 }
 
@@ -10237,7 +10284,7 @@ rb_thread_save_context(rb_thread_t th)
 
     th->frame = ruby_frame;
     th->scope = ruby_scope;
-    ruby_scope->flags |= SCOPE_DONT_RECYCLE;
+    SCOPE_FLAGS(ruby_scope) |= SCOPE_DONT_RECYCLE;
     th->wrapper = ruby_wrapper;
     th->cref = ruby_cref;
     th->dyna_vars = ruby_dyna_vars;
Index: gc.c
===================================================================
RCS file: /src/ruby/gc.c,v
retrieving revision 1.239
diff -u -p -r1.239 gc.c
--- gc.c	15 Jun 2006 16:41:28 -0000	1.239
+++ gc.c	30 Jun 2006 03:43:06 -0000
@@ -983,7 +983,7 @@ gc_mark_children(VALUE ptr, int lev)
 	goto again;
 
       case T_SCOPE:
-	if (obj->as.scope.local_vars && (obj->as.scope.flags & SCOPE_MALLOC)) {
+	if (obj->as.scope.local_vars && (SCOPE_FLAGS(obj) & SCOPE_MALLOC)) {
 	    int n = obj->as.scope.local_tbl[0]+1;
 	    VALUE *vars = &obj->as.scope.local_vars[-1];
 
@@ -991,6 +991,8 @@ gc_mark_children(VALUE ptr, int lev)
 		gc_mark(*vars++, lev);
 	    }
 	}
+	if (obj->as.scope.prev)
+	    gc_mark((VALUE) obj->as.scope.prev, lev);
 	break;
 
       case T_STRUCT:
@@ -1240,11 +1242,11 @@ obj_free(VALUE obj)
 
       case T_SCOPE:
 	if (RANY(obj)->as.scope.local_vars &&
-            RANY(obj)->as.scope.flags != SCOPE_ALLOCA) {
+            SCOPE_FLAGS(obj) != SCOPE_ALLOCA) {
 	    VALUE *vars = RANY(obj)->as.scope.local_vars-1;
 	    if (vars[0] == 0)
 		RUBY_CRITICAL(free(RANY(obj)->as.scope.local_tbl));
-	    if (RANY(obj)->as.scope.flags & SCOPE_MALLOC)
+	    if (SCOPE_FLAGS(obj) & SCOPE_MALLOC)
 		RUBY_CRITICAL(free(vars));
 	}
 	break;
Index: parse.y
===================================================================
RCS file: /src/ruby/parse.y,v
retrieving revision 1.446
diff -u -p -r1.446 parse.y
--- parse.y	28 Jun 2006 00:23:56 -0000	1.446
+++ parse.y	30 Jun 2006 03:43:07 -0000
@@ -8006,7 +8006,7 @@ top_local_setup_gen(struct parser_params
 	i = ruby_scope->local_tbl?ruby_scope->local_tbl[0]:0;
 
 	if (i < len) {
-	    if (i == 0 || (ruby_scope->flags & SCOPE_MALLOC) == 0) {
+	    if (i == 0 || (SCOPE_FLAGS(ruby_scope) & SCOPE_MALLOC) == 0) {
 		VALUE *vars = ALLOC_N(VALUE, len+1);
 		if (ruby_scope->local_vars) {
 		    *vars++ = ruby_scope->local_vars[-1];
@@ -8018,7 +8018,7 @@ top_local_setup_gen(struct parser_params
 		    rb_mem_clear(vars, len);
 		}
 		ruby_scope->local_vars = vars;
-		ruby_scope->flags |= SCOPE_MALLOC;
+		SCOPE_FLAGS(ruby_scope) |= SCOPE_MALLOC;
 	    }
 	    else {
 		VALUE *vars = ruby_scope->local_vars-1;
Index: sample/test.rb
===================================================================
RCS file: /src/ruby/sample/test.rb,v
retrieving revision 1.99
diff -u -p -r1.99 test.rb
--- sample/test.rb	27 Jun 2006 14:02:26 -0000	1.99
+++ sample/test.rb	30 Jun 2006 03:43:09 -0000
@@ -2200,6 +2200,26 @@ l = []
 GC.start
 test_ok true   # reach here or dumps core
 
+def return_x_and_y
+  return eval("[x, y]", Binding.of_caller)
+end
+obj = Object.new
+def obj.return_self_x_and_y
+  return eval("[self, x, y]", Binding.of_caller)
+end
+def obj.return_self_x_and_y_2
+  return Binding.of_caller { |bind|
+    eval("[self, x, y]", bind)
+  }
+end
+x = "abc"
+1.times {
+  y = "def"
+  test_ok(return_x_and_y == [x, y])
+  test_ok(obj.return_self_x_and_y == [self, x, y])
+  test_ok(obj.return_self_x_and_y_2 == [self, x, y])
+}
+
 if $failed > 0
   printf "test: %d failed %d\n", $ntest, $failed
 else
