package codelines; import animation.CodeLine; import animation.ControlFlow; import animation.Memory; import animation.StackFrame; import animation.StackFrame.FrameType; public abstract class WhileLoop extends CodeLine { @Override public ControlFlow runForward(Memory m) { boolean declared = false; // prove if it is the first step in the loop if( !m.isSomewhereDefined( "line_" + lineId + "_index", false ) ) { // first loop step m.declare( "line_" + lineId + "_index", 0, false ); declared = true; } if( !condition( m ) ) // prove if the loop has finished { m.undeclare( "line_" + lineId + "_index", false ); actions.push( (Memory mem) -> { return new ControlFlow( ControlFlow.STEP_OVER ); // loop was not called so nothing to reverse }); return new ControlFlow( ControlFlow.STEP_OVER ); // don't execute the loop body } if( declared ) { m.addFrame( new StackFrame( FrameType.LOOP ) ); actions.push( (Memory mem) -> { mem.removeFrame(); mem.undeclare( "line_" + lineId + "_index", false ); return new ControlFlow( ControlFlow.STEP_OVER ); // step out of the loop } ); } else { if( !condition( m ) ) // prove if loop was finished { StackFrame sf = m.removeFrame(); // remove loop stack m.undeclare( "line_" + lineId + "_index", false ); actions.push( (Memory mem) -> { mem.declare( "line_" + lineId + "_index", 0, false ); mem.addFrame( sf ); // restore last loop stack return new ControlFlow( ControlFlow.STEP_INTO ); // step into the loop body }); return new ControlFlow( ControlFlow.STEP_OVER ); // step out of the loop } StackFrame old = m.removeFrame(); // fresh stack frame for loop body m.addFrame( new StackFrame( FrameType.LOOP ) ); actions.push( (Memory mem) -> { mem.removeFrame(); mem.addFrame( old ); return new ControlFlow( ControlFlow.STEP_INTO ); }); } return new ControlFlow( ControlFlow.STEP_INTO ); } abstract protected boolean condition( Memory m ); }