Index: src/org/jruby/evaluator/EvaluateVisitor.java
===================================================================
RCS file: /cvsroot/jruby/jruby/src/org/jruby/evaluator/EvaluateVisitor.java,v
retrieving revision 1.71.2.3
diff -u -r1.71.2.3 EvaluateVisitor.java
--- src/org/jruby/evaluator/EvaluateVisitor.java	6 Jan 2006 00:00:41 -0000	1.71.2.3
+++ src/org/jruby/evaluator/EvaluateVisitor.java	7 Jan 2006 01:00:46 -0000
@@ -403,18 +403,29 @@
     }
     private static final BlockPassNodeVisitor blockPassNodeVisitor = new BlockPassNodeVisitor();
     
+    private static interface Breakable {
+    }
+    
     // Not collapsed, will require exception handling
     private static class BreakNodeVisitor implements Instruction {
     	public void execute(EvaluationState state, InstructionContext ctx) {
     		BreakNode iVisited = (BreakNode)ctx;
     		
-            JumpException je = new JumpException(JumpException.JumpType.BreakJump);
-            if (iVisited.getValueNode() != null) {
-                je.setPrimaryData(state.begin(iVisited.getValueNode()));
-            } else {
-            	je.setPrimaryData(state.runtime.getNil());
+            // pop everything but nearest breakable
+            while (!(state.peekCurrentInstruction() instanceof Breakable)) {
+                state.popCurrentNodeAndVisitor();
             }
-            throw je;
+            
+            // pop breakable and push value node
+            state.popCurrentNodeAndVisitor();
+            state.addNodeInstruction(iVisited.getValueNode());
+//            JumpException je = new JumpException(JumpException.JumpType.BreakJump);
+//            if (iVisited.getValueNode() != null) {
+//                je.setPrimaryData(state.begin(iVisited.getValueNode()));
+//            } else {
+//            	je.setPrimaryData(state.runtime.getNil());
+//            }
+//            throw je;
     	}
     }
     private static final BreakNodeVisitor breakNodeVisitor = new BreakNodeVisitor();
@@ -1452,11 +1463,18 @@
     private static class NextNodeVisitor implements Instruction {
     	public void execute(EvaluationState state, InstructionContext ctx) {
     		NextNode iVisited = (NextNode)ctx;
-    		JumpException je = new JumpException(JumpException.JumpType.NextJump);
-            if (iVisited.getValueNode() != null) {
-                je.setPrimaryData(state.begin(iVisited.getValueNode()));
+            
+            while (!(state.peekCurrentInstruction() instanceof Redoable)) {
+                state.popCurrentNodeAndVisitor();
             }
-            throw je;
+            
+            // pop the redoable and continue
+            state.popCurrentNodeAndVisitor();
+//    		JumpException je = new JumpException(JumpException.JumpType.NextJump);
+//            if (iVisited.getValueNode() != null) {
+//                je.setPrimaryData(state.begin(iVisited.getValueNode()));
+//            }
+//            throw je;
     	}
     }
     private static final NextNodeVisitor nextNodeVisitor = new NextNodeVisitor();
@@ -1608,10 +1626,22 @@
     }
     private static final OrNodeVisitor orNodeVisitor = new OrNodeVisitor();
     
+    private static interface Redoable {
+    }
+    
     // Not collapsed, pure exception stuff
     private static class RedoNodeVisitor implements Instruction {
     	public void execute(EvaluationState state, InstructionContext ctx) {
-            throw new JumpException(JumpException.JumpType.RedoJump);
+           while (!(state.peekCurrentInstruction() instanceof Redoable)) {
+               state.popCurrentNodeAndVisitor();
+           }
+           
+           // pop the redoable leave the redo body
+           InstructionContext nodeToRedo = state.peekCurrentInstructionContext();
+           state.popCurrentNodeAndVisitor();
+           state.addNodeInstruction(nodeToRedo, redoThingy);
+           state.addNodeInstruction(nodeToRedo);
+            //throw new JumpException(JumpException.JumpType.RedoJump);
     	}
     }
     private static final RedoNodeVisitor redoNodeVisitor = new RedoNodeVisitor();
@@ -1977,37 +2007,68 @@
     }
     private static final VCallNodeVisitor vCallNodeVisitor = new VCallNodeVisitor();
     
+    private static class WhileConditionCheck implements Instruction, Breakable {
+        public void execute(EvaluationState state, InstructionContext ctx) {
+            WhileNode iVisited = (WhileNode)ctx;
+            
+            // result contains condition check
+            IRubyObject condition = state.getResult();
+            
+            if (condition.isTrue()) {
+                // re-push body, condition, and check
+                state.addNodeInstruction(iVisited, whileConditionCheck);
+                state.addNodeInstruction(iVisited.getConditionNode());
+                state.addNodeInstruction(iVisited.getBodyNode(), redoThingy);
+                state.addNodeInstruction(iVisited.getBodyNode());
+            }
+            // else loop terminates
+        }
+    }
+    private static final WhileConditionCheck whileConditionCheck = new WhileConditionCheck();
+    private static class RedoThingy implements Instruction, Redoable {
+        public void execute(EvaluationState state, InstructionContext ctx) {
+        }
+    }
+    private static final RedoThingy redoThingy = new RedoThingy();
     // Not collapsed, complicated with exceptions
     private static class WhileNodeVisitor implements Instruction {
     	public void execute(EvaluationState state, InstructionContext ctx) {
     		WhileNode iVisited = (WhileNode)ctx;
-            // while do...Initial condition not met do not enter block
-            if (iVisited.evaluateAtStart() && 
-                state.begin(iVisited.getConditionNode()).isTrue() == false) {
-                return;
-            }
             
-            do {
-                while (true) { // Used for the 'redo' command
-                    try {
-                        state.begin(iVisited.getBodyNode());
-                        break;
-                    } catch (JumpException je) {
-                    	if (je.getJumpType() == JumpException.JumpType.RedoJump) {
-                    		// When a 'redo' is reached eval body of loop again.
-                    		continue;
-                    	} else if (je.getJumpType() == JumpException.JumpType.NextJump) {
-                    		// When a 'next' is reached ceck condition of loop again.
-                    		break;
-                    	} else if (je.getJumpType() == JumpException.JumpType.BreakJump) {
-	                        // When a 'break' is reached leave loop.
-	                        return;
-                    	} else {
-                    		throw je;
-                    	}
-                    }
-                }
-            } while (state.begin(iVisited.getConditionNode()).isTrue());
+            if (iVisited.evaluateAtStart()) {
+                state.addNodeInstruction(iVisited, whileConditionCheck);
+                state.addNodeInstruction(iVisited.getConditionNode());
+            }
+
+            state.addNodeInstruction(iVisited.getBodyNode(), redoThingy);
+            state.addNodeInstruction(iVisited.getBodyNode());
+            // while do...Initial condition not met do not enter block
+//            if (iVisited.evaluateAtStart() && 
+//                state.begin(iVisited.getConditionNode()).isTrue() == false) {
+//                return;
+//            }
+//            
+//            do {
+//                while (true) { // Used for the 'redo' command
+//                    try {
+//                        state.begin(iVisited.getBodyNode());
+//                        break;
+//                    } catch (JumpException je) {
+//                    	if (je.getJumpType() == JumpException.JumpType.RedoJump) {
+//                    		// When a 'redo' is reached eval body of loop again.
+//                    		continue;
+//                    	} else if (je.getJumpType() == JumpException.JumpType.NextJump) {
+//                    		// When a 'next' is reached ceck condition of loop again.
+//                    		break;
+//                    	} else if (je.getJumpType() == JumpException.JumpType.BreakJump) {
+//	                        // When a 'break' is reached leave loop.
+//	                        return;
+//                    	} else {
+//                    		throw je;
+//                    	}
+//                    }
+//                }
+//            } while (state.begin(iVisited.getConditionNode()).isTrue());
     	}
     }
     private static final WhileNodeVisitor whileNodeVisitor = new WhileNodeVisitor();
Index: src/org/jruby/evaluator/EvaluationState.java
===================================================================
RCS file: /cvsroot/jruby/jruby/src/org/jruby/evaluator/EvaluationState.java,v
retrieving revision 1.6.2.4
diff -u -r1.6.2.4 EvaluationState.java
--- src/org/jruby/evaluator/EvaluationState.java	6 Jan 2006 00:00:41 -0000	1.6.2.4
+++ src/org/jruby/evaluator/EvaluationState.java	7 Jan 2006 01:00:46 -0000
@@ -43,6 +43,14 @@
     public IRubyObject deaggregateResult() {
         return (IRubyObject)results.pop();
     }
+    
+    public Instruction peekCurrentInstruction() {
+        return (Instruction)getCurrentNodeVisitorStack().peek();
+    }
+    
+    public InstructionContext peekCurrentInstructionContext() {
+        return (InstructionContext)getCurrentNodeStack().peek();
+    }
 	
 	/**
 	 * Mark the current stack position as "wanting return". When a return is encountered,
@@ -232,7 +240,13 @@
             try {
                 // for each call to internalEval, push down new stacks (to isolate eval runs that still want to be logically separate
                 pushCurrentNodeStacks();
-                
+//                StackTraceElement[] stes = new Exception().getStackTrace();
+//                // search backward for last call to begin()
+//                for (int i = stes.length - 2; i >= 0; i--) {
+//                    if (stes[i].getClassName().indexOf("EvaluationState") != -1 && stes[i].getMethodName().equals("begin")) {
+//                        System.out.println("" + (stes.length - i) + " frames");
+//                    }
+//                }
                 addNodeInstruction(node);
                 
                 // TODO: once we're ready to have an external entity run this loop (i.e. thread scheduler) move this out
@@ -251,6 +265,38 @@
         return getResult();
     }
 
+    public IRubyObject beginLite(Node node) {
+        clearResult();
+        
+        if (node != null) {
+            try {
+                // for each call to internalEval, push down new stacks (to isolate eval runs that still want to be logically separate
+                //pushCurrentNodeStacks();
+//                StackTraceElement[] stes = new Exception().getStackTrace();
+//                // search backward for last call to begin()
+//                for (int i = stes.length - 2; i >= 0; i--) {
+//                    if (stes[i].getClassName().indexOf("EvaluationState") != -1 && stes[i].getMethodName().equals("begin")) {
+//                        System.out.println("" + (stes.length - i) + " frames");
+//                    }
+//                }
+                addNodeInstruction(node);
+                
+                // TODO: once we're ready to have an external entity run this loop (i.e. thread scheduler) move this out
+                while (hasNext()) {                 
+                    // invoke the next instruction
+                    executeNext();
+                }
+            } catch (StackOverflowError soe) {
+                // TODO: perhaps a better place to catch this (although it will go away)
+                throw runtime.newSystemStackError("stack level too deep");
+            } finally {
+                //popCurrentNodeStacks();
+            }
+        }
+        
+        return getResult();
+    }
+
     public void begin2(Node node) {
         clearResult();
     
