From Yukihiro Matsumoto
<987637838.835665.2921.nullmailer / ev.netlab.zetabits.com>
> |		print "a: #{a}\n"	# Name Error
> |
> | it will the first time compile the part between #{}. Because for this
> |iteration a was never assigned, it don't exist and ruby resolve it as a
> |function call. This is why it give an error.
> 
> That's what's happening.
> 
> But I feel it's a bug, or at most misfeature.  eval() should execute
> as if the evaluating string is embedded in the code, so that the error
> in this case is not what I expect.  But I found it's pretty hard to
> fix.  It will remain as it is until I reimplement the core in the
> future version.  Sorry.

Probably, I could fix it.

In this method, only values are cleared without removing dyna-var objects
at the end of rb_yield_0, and used in the next rb_yield_0 call.
It is not a good method because the argument "acheck" of rb_yield_0
is being referred to to do the decision of yield-call or proc/thread-call.

It took two hours to write this "English" mail.


[0,1].each {|n|
  print "n: #{n}\n"
  case n
  when 0
    a = 0
    print "a: #{a}\n"       # => 0
  when 1
    b = 1
    print "a: #{a}\n"       # => "a: "   (a == nil)
    print "b: #{b}\n"
  end
}


--- eval.c.orig	Wed Apr 18 00:35:04 2001
+++ eval.c	Thu Apr 19 18:16:38 2001
@@ -3601,17 +3601,47 @@
 	}
     }
 #else
-    if (ruby_dyna_vars && (block->flags & BLOCK_D_SCOPE) &&
-	!FL_TEST(ruby_dyna_vars, DVAR_DONT_RECYCLE)) {
-	struct RVarmap *vars = ruby_dyna_vars;
+    if ((block->flags & BLOCK_D_SCOPE) && ruby_dyna_vars) {
+	struct RVarmap *vars;
 
-	if (ruby_dyna_vars->id == 0) {
-	    vars = ruby_dyna_vars->next;
-	    rb_gc_force_recycle((VALUE)ruby_dyna_vars);
-	    while (vars && vars->id != 0) {
-		struct RVarmap *tmp = vars->next;
-		rb_gc_force_recycle((VALUE)vars);
-		vars = tmp;
+	if (acheck) { /* acheck == true : proc_call or thread_yield */
+	    if (!FL_TEST(ruby_dyna_vars, DVAR_DONT_RECYCLE)) {
+		vars = ruby_dyna_vars;
+		if (vars->id == 0) {
+		    vars = ruby_dyna_vars->next;
+		    rb_gc_force_recycle((VALUE)ruby_dyna_vars);
+		    while (vars && vars->id != 0) {
+			struct RVarmap *tmp = vars->next;
+			rb_gc_force_recycle((VALUE)vars);
+			vars = tmp;
+		    }
+		}
+	    }
+	}
+	else { /* acheck == false : normal yield */
+	    if (FL_TEST(ruby_dyna_vars, DVAR_DONT_RECYCLE)) {
+		/* copy dyna-vars-list for next yield */
+	 	if (ruby_dyna_vars->next && ruby_dyna_vars->next->id != 0) {
+		    vars = ruby_dyna_vars->next;
+		    vars = new_dvar(vars->id, Qnil, vars->next);
+		    block->dyna_vars = vars;
+		    for (; vars; vars = vars->next) {
+			if (!vars->next || vars->next->id == 0) break;
+			vars->next = new_dvar(vars->next->id, Qnil, vars->next->next);
+		    }
+		}
+	    }
+	    else {
+		/* clear dyna-vars value for next yield */
+		vars = ruby_dyna_vars;
+		if (vars->id == 0) {
+		    block->dyna_vars = vars = ruby_dyna_vars->next;
+		    rb_gc_force_recycle((VALUE)ruby_dyna_vars);
+		    while (vars && vars->id != 0) {
+			vars->val = Qnil;
+			vars = vars->next;
+		    }
+		}
 	    }
 	}
     }
----
K.Kosako