Prechádzať zdrojové kódy

ReadOnly Access for Memory Instances

Kolja Strohm 6 rokov pred
rodič
commit
4a8225a7c5

+ 25 - 1
src/animation/Memory.java

@@ -12,16 +12,40 @@ public class Memory {
         LOCAL
     }
     
+    public class ReadOnlyMemory
+    {
+        public <T> T read( String name, MemoryType type )
+        {
+            return Memory.this.read( name, type );
+        }
+        
+        public boolean isSomewhereDefined( String name, MemoryType type )
+        {
+            return Memory.this.isSomewhereDefined( name, type );
+        }
+        
+        public boolean isDefined( String name, MemoryType type )
+        {
+            return Memory.this.isDefined( name, type );
+        }
+    }
+    
     private StackFrame global;
     private Stack< StackFrame > stack;
     
+    
     public Memory()
     {
         stack = new Stack<StackFrame>();
         global = new StackFrame( FrameType.FUNCTION );
     }
     
-    public int getSize()
+    public ReadOnlyMemory createReadOnlyMemory()
+    {
+        return new ReadOnlyMemory();
+    }
+    
+    public int getSize() 
     {
         return stack.size();
     }

+ 13 - 12
src/bk/BKNodePlacement.java

@@ -11,6 +11,7 @@ import animation.Memory;
 import animation.PseudoCodeNode;
 import animation.PseudoCodeProcessor;
 import animation.Memory.MemoryType;
+import animation.Memory.ReadOnlyMemory;
 import codelines.DeclareVariable;
 import codelines.FunctionCall;
 import codelines.FunctionDefinition;
@@ -86,31 +87,31 @@ public class BKNodePlacement extends AnimatedAlgorithm {
         PseudoCodeNode combine = new Combine().createPseudocodeTree( tree );
         root.add( mainFunction );
         mainFunction.add( new PseudoCodeNode( TextLayoutHelper.setupPseudoCode( "call detectConflicts( graph )", vars ), tree, new FunctionCall( conflictDetectionFunction, new String[]{ "graph" } ) ) );
-        mainFunction.add( new PseudoCodeNode( TextLayoutHelper.setupPseudoCode( "layout = TOP_LEFT", vars ), tree, new DeclareVariable<String>( "layout" ) {
+        mainFunction.add( new PseudoCodeNode( TextLayoutHelper.setupPseudoCode( "layout = DOWN_RIGHT", vars ), tree, new DeclareVariable<String>( "layout" ) {
             @Override
-            protected String value(Memory m) {
-                return "TOP_LEFT";
+            protected String value(ReadOnlyMemory m) {
+                return "DOWN_RIGHT";
             }
         }) );
         mainFunction.add( new PseudoCodeNode( TextLayoutHelper.setupPseudoCode( "call calcLayout( layout, graph )", vars ), tree, new FunctionCall( calcLayout, new String[]{ "layout", "graph" } ) ) );
-        mainFunction.add( new PseudoCodeNode( TextLayoutHelper.setupPseudoCode( "layout = TOP_RIGHT", vars ), tree, new SetVariable<String>( "layout" ) {
+        mainFunction.add( new PseudoCodeNode( TextLayoutHelper.setupPseudoCode( "layout = DOWN_LEFT", vars ), tree, new SetVariable<String>( "layout" ) {
             @Override
-            protected String value(Memory m) {
-                return "TOP_RIGHT";
+            protected String value(ReadOnlyMemory m) {
+                return "DOWN_LEFT";
             }
         }) );
         mainFunction.add( new PseudoCodeNode( TextLayoutHelper.setupPseudoCode( "call calcLayout( layout, graph )", vars ), tree, new FunctionCall( calcLayout, new String[]{ "layout", "graph" } ) ) );
-        mainFunction.add( new PseudoCodeNode( TextLayoutHelper.setupPseudoCode( "layout = BOTTOM_LEFT", vars ), tree, new SetVariable<String>( "layout" ) {
+        mainFunction.add( new PseudoCodeNode( TextLayoutHelper.setupPseudoCode( "layout = UP_RIGHT", vars ), tree, new SetVariable<String>( "layout" ) {
             @Override
-            protected String value(Memory m) {
-                return "BOTTOM_LEFT";
+            protected String value(ReadOnlyMemory m) {
+                return "UP_RIGHT";
             }
         }) );
         mainFunction.add( new PseudoCodeNode( TextLayoutHelper.setupPseudoCode( "call calcLayout( layout, graph )", vars ), tree, new FunctionCall( calcLayout, new String[]{ "layout", "graph" } ) ) );
-        mainFunction.add( new PseudoCodeNode( TextLayoutHelper.setupPseudoCode( "layout = BOTTOM_RIGHT", vars ), tree, new SetVariable<String>( "layout" ) {
+        mainFunction.add( new PseudoCodeNode( TextLayoutHelper.setupPseudoCode( "layout = UP_LEFT", vars ), tree, new SetVariable<String>( "layout" ) {
             @Override
-            protected String value(Memory m) {
-                return "BOTTOM_RIGHT";
+            protected String value(ReadOnlyMemory m) {
+                return "UP_LEFT";
             }
         }) );
         mainFunction.add( new PseudoCodeNode( TextLayoutHelper.setupPseudoCode( "call calcLayout( layout, graph )", vars ), tree, new FunctionCall( calcLayout, new String[]{ "layout", "graph" } ) ) );

+ 63 - 1
src/bk/BlockCalc.java

@@ -1,10 +1,17 @@
 package bk;
 
+import java.util.ArrayList;
+
 import javax.swing.JTree;
 
 import animation.AlgorithmStage;
 import animation.PseudoCodeNode;
+import animation.Memory.MemoryType;
+import animation.Memory.ReadOnlyMemory;
+import codelines.AbstractForLoop;
+import codelines.DeclareVariable;
 import codelines.FunctionDefinition;
+import graph.LayeredGraphNode;
 import lib.TextLayoutHelper;
 
 /**
@@ -18,7 +25,62 @@ public class BlockCalc implements AlgorithmStage {
     public PseudoCodeNode createPseudocodeTree( JTree tree ) {
         String[] vars = { "graph", "L", "v", "r", "neighbors", "layout" };
         PseudoCodeNode root = new PseudoCodeNode( TextLayoutHelper.setupPseudoCode( "function calculateBlockGraph( graph, layout )", vars ), tree, new FunctionDefinition( new String[]{ "graph", "layout" } ) );
-        
+        root.add( new PseudoCodeNode(TextLayoutHelper.setupPseudoCode( "L = graph.getContainedLayers();", vars), tree, new DeclareVariable<ArrayList<ArrayList<LayeredGraphNode>>>( "L" ) {
+            @Override
+            protected ArrayList<ArrayList<LayeredGraphNode>> value(ReadOnlyMemory m) {
+                return m.<LayeredGraphNode>read( "graph", MemoryType.LOCAL ).getContainedLayers();
+            }
+        } ) );
+        PseudoCodeNode layerLoop = new PseudoCodeNode( TextLayoutHelper.setupPseudoCode( "for i=layout.contains('DOWN') ? 0 : |L|-1 to layout.contains('DOWN') ? |L|-1 : 0 do", vars ), tree, new AbstractForLoop<Integer>( "i" ) {
+            @Override
+            protected Integer begin(ReadOnlyMemory m) {
+                if( m.<String>read( "layout", MemoryType.LOCAL ).contains( "DOWN" ) )
+                    return 0;
+                return m.<ArrayList<ArrayList<LayeredGraphNode>>>read( "L", MemoryType.LOCAL ).size() - 1;
+            }
+            @Override
+            protected Integer step(ReadOnlyMemory m) {
+                if( m.<String>read( "layout", MemoryType.LOCAL ).contains( "DOWN" ) )
+                    return m.<Integer>read( "i", MemoryType.LOCAL ) + 1;
+                return m.<Integer>read( "i", MemoryType.LOCAL ) - 1;
+            }
+            @Override
+            protected boolean condition(ReadOnlyMemory m) {
+                if( m.<String>read( "layout", MemoryType.LOCAL ).contains( "DOWN" ) )
+                    return m.<Integer>read( "i", MemoryType.LOCAL ) <= m.<ArrayList<ArrayList<LayeredGraphNode>>>read( "L", MemoryType.LOCAL ).size() - 1;
+                return m.<Integer>read( "i", MemoryType.LOCAL ) >= 0;
+            }
+        });
+        root.add( layerLoop );
+        layerLoop.add( new PseudoCodeNode(TextLayoutHelper.setupPseudoCode( "r = layout.contains('RIGHT') ? -1 : INFINITY;", vars), tree, new DeclareVariable<Double>( "r" ) {
+            @Override
+            protected Double value(ReadOnlyMemory m) {
+                if( m.<String>read( "layout", MemoryType.LOCAL ).contains( "RIGHT" ) )
+                    return -1.0;
+                return Double.POSITIVE_INFINITY;
+            }
+        } ) );
+        PseudoCodeNode nodeLoop = new PseudoCodeNode( TextLayoutHelper.setupPseudoCode( "for k=layout.contains('RIGHT') ? 0 : |L[i]|-1 to layout.contains('RIGHT') ? |L[i]|-1 : 0 do", vars ), tree, new AbstractForLoop<Integer>( "i" ) {
+            @Override
+            protected Integer begin( ReadOnlyMemory m) {
+                if( m.<String>read( "layout", MemoryType.LOCAL ).contains( "RIGHT" ) )
+                    return 0;
+                return m.<ArrayList<ArrayList<LayeredGraphNode>>>read( "L", MemoryType.LOCAL ).get( m.read( "i", MemoryType.LOCAL ) ).size() - 1;
+            }
+            @Override
+            protected Integer step( ReadOnlyMemory m) {
+                if( m.<String>read( "layout", MemoryType.LOCAL ).contains( "RIGHT" ) )
+                    return m.<Integer>read( "k", MemoryType.LOCAL ) + 1;
+                return m.<Integer>read( "k", MemoryType.LOCAL ) - 1;
+            }
+            @Override
+            protected boolean condition( ReadOnlyMemory m) {
+                if( m.<String>read( "layout", MemoryType.LOCAL ).contains( "RIGHT" ) )
+                    return m.<Integer>read( "k", MemoryType.LOCAL ) <= m.<ArrayList<ArrayList<LayeredGraphNode>>>read( "L", MemoryType.LOCAL ).get( m.read( "i", MemoryType.LOCAL ) ).size() - 1;
+                return m.<Integer>read( "k", MemoryType.LOCAL ) >= 0;
+            }
+        });
+        layerLoop.add( nodeLoop );
         return root;
     }
 }

+ 22 - 25
src/bk/ConflictDetection.java

@@ -11,6 +11,7 @@ import animation.ControlFlow;
 import animation.Memory;
 import animation.PseudoCodeNode;
 import animation.Memory.MemoryType;
+import animation.Memory.ReadOnlyMemory;
 import bk.BKNodePlacement.State;
 import bk.LayoutType;
 import codelines.DeclareVariable;
@@ -111,14 +112,14 @@ public class ConflictDetection implements AlgorithmStage {
         root.add( text );
         PseudoCodeNode foreach = new PseudoCodeNode( TextLayoutHelper.setupPseudoCode( "foreach n in graph.getContainedNodes() do", vars ), tree, new ForEachLoop<LayeredGraphNode>( "n" ) {
 			@Override
-			protected List<LayeredGraphNode> list(Memory m) {
+			protected List<LayeredGraphNode> list(ReadOnlyMemory m) {
 				return m.<LayeredGraphNode>read( "graph", MemoryType.LOCAL ).getContainedNodes();
 			}
         } );
         root.add( foreach );
         PseudoCodeNode ifNode = new PseudoCodeNode( TextLayoutHelper.setupPseudoCode( "if n has subgraph then", vars ), tree, new IfLoop() {
 			@Override
-			protected boolean condition(Memory m) {
+			protected boolean condition(ReadOnlyMemory m) {
 				return m.<LayeredGraphNode>read( "n", MemoryType.LOCAL ).getContainedLayers().size() > 0;
 			}
         } );
@@ -127,24 +128,20 @@ public class ConflictDetection implements AlgorithmStage {
         ifNode.add( call );
         text = new PseudoCodeNode(TextLayoutHelper.setupPseudoCodeStage( "-- mark conflicts in graph --" ), tree, new Kommentar() );
         root.add( text );
-        PseudoCodeNode init = new PseudoCodeNode(TextLayoutHelper.setupPseudoCode( "L = graph.getContainedLayers();", vars), tree, new CodeLine() {
-			@Override
-			public ControlFlow runForward(Memory m) {
-				m.declare( "L", m.<LayeredGraphNode>read( "graph", MemoryType.LOCAL ).getContainedLayers(), MemoryType.LOCAL );
-				actions.push( (Memory mem) -> {
-					mem.undeclare( "L", MemoryType.LOCAL );
-				} );
-				return new ControlFlow( ControlFlow.STEP_OVER );
-			}
+        PseudoCodeNode init = new PseudoCodeNode(TextLayoutHelper.setupPseudoCode( "L = graph.getContainedLayers();", vars), tree, new DeclareVariable<ArrayList<ArrayList<LayeredGraphNode>>>( "L" ) {
+            @Override
+            protected ArrayList<ArrayList<LayeredGraphNode>> value(ReadOnlyMemory m) {
+                return m.<LayeredGraphNode>read( "graph", MemoryType.LOCAL ).getContainedLayers();
+            }
         } );
         root.add( init );
         PseudoCodeNode outerLoop = new PseudoCodeNode( TextLayoutHelper.setupPseudoCode( "for i=1 to |L|-2 do", vars ), tree, new ForLoop( "i" ) {
 			@Override
-			protected int minimum( Memory m ) {
+			protected int minimum( ReadOnlyMemory m ) {
 				return 1;
 			}
 			@Override
-			protected int maximum( Memory m ) {
+			protected int maximum( ReadOnlyMemory m ) {
 				return m.<ArrayList<ArrayList<LayeredGraphNode>>>read( "L", MemoryType.LOCAL ).size() - 2;
 			}
         } );
@@ -164,18 +161,18 @@ public class ConflictDetection implements AlgorithmStage {
         outerLoop.add( line );
         PseudoCodeNode innerLoop = new PseudoCodeNode( TextLayoutHelper.setupPseudoCode( "for l1=0 to |L[i+1]|-1 do", vars ), tree, new ForLoop( "l1" ) {
 			@Override
-			protected int minimum(Memory m) {
+			protected int minimum(ReadOnlyMemory m) {
 				return 0;
 			}
 			@Override
-			protected int maximum(Memory m) {
+			protected int maximum(ReadOnlyMemory m) {
 				return m.<ArrayList<ArrayList<LayeredGraphNode>>>read( "L", MemoryType.LOCAL ).get( m.<Integer>read( "i", MemoryType.LOCAL ) + 1 ).size() - 1;
 			}
         } );
         outerLoop.add( innerLoop );
         ifNode = new PseudoCodeNode( TextLayoutHelper.setupPseudoCode( "if l1==|L[i+1]|-1 or L[i+1][l1] incident to inner segment between L[i+1] and L[i] then", vars ), tree, new IfLoop() {
 			@Override
-			protected boolean condition(Memory m) {
+			protected boolean condition(ReadOnlyMemory m) {
 	            return m.<Integer>read( "l1", MemoryType.LOCAL ) == m.<LayeredGraphNode>read( "graph", MemoryType.LOCAL ).getContainedLayers().get( m.<Integer>read( "i", MemoryType.LOCAL ) + 1).size() - 1 || 
 	            		incidentToInnerSegmentBetweenLiPlusOneAndLi( m );
 			}
@@ -183,14 +180,14 @@ public class ConflictDetection implements AlgorithmStage {
         innerLoop.add( ifNode );
         line = new PseudoCodeNode( TextLayoutHelper.setupPseudoCode( "k1 = |L[i]|-1;", vars ), tree, new DeclareVariable<Integer>( "k1" ) {
 			@Override
-			protected Integer value(Memory m) {
+			protected Integer value(ReadOnlyMemory m) {
 				return (int)m.<ArrayList<ArrayList<LayeredGraphNode>>>read( "L", MemoryType.LOCAL ).get( m.read( "i", MemoryType.LOCAL ) ).size() - 1;
 			}
         } );
         ifNode.add( line );
         PseudoCodeNode innerIfNode = new PseudoCodeNode( TextLayoutHelper.setupPseudoCode( "if L[i+1][l1] incident to inner segment between L[i+1] and L[i] then", vars ), tree, new IfLoop() {
 			@Override
-			protected boolean condition(Memory m) {
+			protected boolean condition(ReadOnlyMemory m) {
 				return incidentToInnerSegmentBetweenLiPlusOneAndLi( m );
 			}
 		} );
@@ -198,7 +195,7 @@ public class ConflictDetection implements AlgorithmStage {
         
         line = new PseudoCodeNode( TextLayoutHelper.setupPseudoCode( "k1 = pos(pred(L[i+1][l1])[0]);", vars ), tree, new SetVariable<Integer>( "k1" ) {
 			@Override
-			protected Integer value(Memory m) {
+			protected Integer value(ReadOnlyMemory m) {
 				return (int)m.<LayeredGraphNode>read( "graph", MemoryType.LOCAL ).getContainedLayers().get( m.read( "i", MemoryType.LOCAL ) ).indexOf(
 						m.<LayeredGraphNode>read( "graph", MemoryType.LOCAL ).getContainedLayers().get( m.<Integer>read( "i", MemoryType.LOCAL ) + 1 ).get( m.read( "l1", MemoryType.LOCAL ) ).getSortedIncomingEdges().get( 0 ).getSources().get( 0 ) );
 			}
@@ -206,21 +203,21 @@ public class ConflictDetection implements AlgorithmStage {
         innerIfNode.add( line );
         PseudoCodeNode whileLoop = new PseudoCodeNode( TextLayoutHelper.setupPseudoCode( "while l <= l1 do", vars ), tree, new WhileLoop() {
 			@Override
-			protected boolean condition( Memory m ) {
+			protected boolean condition( ReadOnlyMemory m ) {
 				return m.<Integer>read( "l", MemoryType.LOCAL ) <= m.<Integer>read( "l1", MemoryType.LOCAL );
 			}
         } );
         ifNode.add( whileLoop );
         foreach = new PseudoCodeNode( TextLayoutHelper.setupPseudoCode( "foreach v in pred(L[i+1][l]) do", vars ), tree, new ForEachLoop<LayeredGraphEdge>( "v" ) {
 			@Override
-			protected List<LayeredGraphEdge> list(Memory m) {
+			protected List<LayeredGraphEdge> list(ReadOnlyMemory m) {
 				return m.<LayeredGraphNode>read( "graph", MemoryType.LOCAL ).getContainedLayers().get( m.<Integer>read( "i", MemoryType.LOCAL ) + 1 ).get( m.read( "l", MemoryType.LOCAL ) ).getIncomingEdges();
 			}
         } );
         whileLoop.add( foreach );
         innerIfNode = new PseudoCodeNode( TextLayoutHelper.setupPseudoCode( "if pos(v) < k0 or pos(v) > k1 then", vars ), tree, new IfLoop() {
 			@Override
-			protected boolean condition(Memory m) {
+			protected boolean condition(ReadOnlyMemory m) {
 			    int k = m.<LayeredGraphNode>read( "graph", MemoryType.LOCAL ).getContainedLayers().get( m.read( "i", MemoryType.LOCAL ) ).indexOf( m.<LayeredGraphEdge>read( "v", MemoryType.LOCAL ).getSources().get( 0 ) );
 				return k < m.<Integer>read( "k0", MemoryType.LOCAL ) || k > m.<Integer>read( "k1", MemoryType.LOCAL );
 			}
@@ -241,14 +238,14 @@ public class ConflictDetection implements AlgorithmStage {
         innerIfNode.add( line );
         line = new PseudoCodeNode( TextLayoutHelper.setupPseudoCode( "l = l+1;", vars ), tree, new SetVariable<Integer>( "l" ) {
 			@Override
-			protected Integer value(Memory m) {
+			protected Integer value(ReadOnlyMemory m) {
 				return (int)m.<Integer>read( "l", MemoryType.LOCAL ) + 1;
 			}
         } );
         whileLoop.add( line );
         line = new PseudoCodeNode( TextLayoutHelper.setupPseudoCode( "k0 = k1;", vars ), tree, new SetVariable<Integer>( "k0" ) {
 			@Override
-			protected Integer value(Memory m) {
+			protected Integer value(ReadOnlyMemory m) {
 				return (int)m.<Integer>read( "k1", MemoryType.LOCAL );
 			}
         } );
@@ -256,7 +253,7 @@ public class ConflictDetection implements AlgorithmStage {
         return root;
     }
     
-    private boolean incidentToInnerSegmentBetweenLiPlusOneAndLi( Memory m ) {
+    private boolean incidentToInnerSegmentBetweenLiPlusOneAndLi( ReadOnlyMemory m ) {
         LayeredGraphNode curr = m.<LayeredGraphNode>read( "graph", MemoryType.LOCAL ).getContainedLayers().get( m.<Integer>read( "i", MemoryType.LOCAL ) + 1 ).get( m.read( "l1", MemoryType.LOCAL ) );
         for (LayeredGraphEdge e : curr.getIncomingEdges()) {
             if (e.isDummyEdge()) {

+ 15 - 10
src/codelines/AbstractForLoop.java

@@ -5,6 +5,7 @@ import animation.ControlFlow;
 import animation.Memory;
 import animation.StackFrame;
 import animation.Memory.MemoryType;
+import animation.Memory.ReadOnlyMemory;
 import animation.StackFrame.FrameType;
 
 public abstract class AbstractForLoop<T> extends CodeLine {
@@ -21,8 +22,8 @@ public abstract class AbstractForLoop<T> extends CodeLine {
         if( !m.isDefined( loopVar, MemoryType.LOCAL ) )
         { // first loop step
             m.addFrame( new StackFrame( FrameType.LOOP ) );
-            m.declare( loopVar, begin( m ), MemoryType.LOCAL ); // set loop variable
-            if( !condition( m ) ) // prove if the loop has finished
+            m.declare( loopVar, begin( m.createReadOnlyMemory() ), MemoryType.LOCAL ); // set loop variable
+            if( !condition( m.createReadOnlyMemory() ) ) // prove if the loop has finished
             {
                 m.removeFrame();
                 actions.push( (Memory mem) -> {} );
@@ -32,28 +33,32 @@ public abstract class AbstractForLoop<T> extends CodeLine {
                 mem.removeFrame();
             } );
         }
-        BackwardAction reverseChange = change( m );
-        if( !condition( m ) ) // prove if loop was finished
+        T next = step( m.createReadOnlyMemory() );
+        T old = m.read( loopVar, MemoryType.LOCAL );
+        m.write( loopVar, next, MemoryType.LOCAL );
+        if( !condition( m.createReadOnlyMemory() ) ) // prove if loop was finished
         {
             StackFrame sf = m.removeFrame(); // remove loop stack
             actions.add( (Memory mem) -> {
                 mem.addFrame( sf ); // restore last loop stack
-                reverseChange.backward( mem );
+                mem.write( loopVar, old, MemoryType.LOCAL );
             });
             return new ControlFlow( ControlFlow.STEP_OVER ); // step out of the loop
         }
-        StackFrame old = m.removeFrame(); // fresh stack frame for loop body
+        StackFrame oldF = m.removeFrame(); // fresh stack frame for loop body
         m.addFrame( new StackFrame( FrameType.LOOP ) );
+        m.declare( loopVar, next, MemoryType.LOCAL );
         actions.push( (Memory mem) -> {
             mem.removeFrame();
-            mem.addFrame( old );
+            mem.addFrame( oldF );
+            mem.write( loopVar, old, MemoryType.LOCAL );
         });
         return new ControlFlow( ControlFlow.STEP_INTO );
     }
     
-    abstract protected T begin( Memory m );
+    abstract protected T begin( ReadOnlyMemory m );
     
-    abstract protected BackwardAction change( Memory m );
+    abstract protected T step( ReadOnlyMemory m );
     
-    abstract protected boolean condition( Memory m );
+    abstract protected boolean condition( final ReadOnlyMemory m );
 }

+ 3 - 2
src/codelines/DeclareVariable.java

@@ -4,6 +4,7 @@ import animation.CodeLine;
 import animation.ControlFlow;
 import animation.Memory;
 import animation.Memory.MemoryType;
+import animation.Memory.ReadOnlyMemory;
 
 public abstract class DeclareVariable <T> extends CodeLine {
 
@@ -20,7 +21,7 @@ public abstract class DeclareVariable <T> extends CodeLine {
 		
 		oldExists = m.isDefined( name, MemoryType.LOCAL );
 		T oldVal = m.read( name, MemoryType.LOCAL );
-		m.declare( name, value( m ), MemoryType.LOCAL );
+		m.declare( name, value( m.createReadOnlyMemory() ), MemoryType.LOCAL );
 		actions.push( (Memory mem) -> {
 			if( !oldExists )
 				mem.undeclare( name, MemoryType.LOCAL );
@@ -30,5 +31,5 @@ public abstract class DeclareVariable <T> extends CodeLine {
 		return new ControlFlow( ControlFlow.STEP_OVER );
 	}
 	
-	abstract protected T value( Memory m );
+	abstract protected T value( ReadOnlyMemory m );
 }

+ 6 - 5
src/codelines/ForEachLoop.java

@@ -7,6 +7,7 @@ import animation.ControlFlow;
 import animation.Memory;
 import animation.StackFrame;
 import animation.Memory.MemoryType;
+import animation.Memory.ReadOnlyMemory;
 import animation.StackFrame.FrameType;
 
 public abstract class ForEachLoop <T> extends CodeLine {
@@ -26,7 +27,7 @@ public abstract class ForEachLoop <T> extends CodeLine {
 			m.declare( "line_" + lineId + "_index", 0, MemoryType.LOCAL );
 			declared = true;
 		}
-		if( m.<Integer>read( "line_" + lineId + "_index", MemoryType.LOCAL ) > list( m ).size() - 1 ) // prove if the loop has finished
+		if( m.<Integer>read( "line_" + lineId + "_index", MemoryType.LOCAL ) > list( m.createReadOnlyMemory() ).size() - 1 ) // prove if the loop has finished
 		{
 			m.undeclare( "line_" + lineId + "_index", MemoryType.LOCAL );
 			actions.push( (Memory mem) -> {});
@@ -35,7 +36,7 @@ public abstract class ForEachLoop <T> extends CodeLine {
 		if( declared )
 		{
 			m.addFrame( new StackFrame( FrameType.LOOP ) );
-            m.declare( loopVar, list( m ).get( m.read( "line_" + lineId + "_index", MemoryType.LOCAL ) ), MemoryType.LOCAL ); // set loop variable
+            m.declare( loopVar, list( m.createReadOnlyMemory() ).get( m.read( "line_" + lineId + "_index", MemoryType.LOCAL ) ), MemoryType.LOCAL ); // set loop variable
 			actions.push( (Memory mem) -> {
 				mem.removeFrame();
 				mem.undeclare( "line_" + lineId + "_index", MemoryType.LOCAL );
@@ -45,7 +46,7 @@ public abstract class ForEachLoop <T> extends CodeLine {
 		{
 			int oldIndex = m.<Integer>read( "line_" + lineId + "_index", MemoryType.LOCAL );
 			m.write( "line_" + lineId + "_index", oldIndex + 1, MemoryType.LOCAL ); // count index down
-			if( m.<Integer>read( "line_" + lineId + "_index", MemoryType.LOCAL ) > list( m ).size() - 1 ) // prove if loop was finished
+			if( m.<Integer>read( "line_" + lineId + "_index", MemoryType.LOCAL ) > list( m.createReadOnlyMemory() ).size() - 1 ) // prove if loop was finished
 			{
 				StackFrame sf = m.removeFrame(); // remove loop stack
 				m.undeclare( "line_" + lineId + "_index", MemoryType.LOCAL );
@@ -57,7 +58,7 @@ public abstract class ForEachLoop <T> extends CodeLine {
 			}
 			StackFrame old = m.removeFrame(); // fresh stack frame for loop body
 			m.addFrame( new StackFrame( FrameType.LOOP ) );
-			m.declare( loopVar, list( m ).get( m.read( "line_" + lineId + "_index", MemoryType.LOCAL ) ), MemoryType.LOCAL ); // update loop variable
+			m.declare( loopVar, list( m.createReadOnlyMemory() ).get( m.read( "line_" + lineId + "_index", MemoryType.LOCAL ) ), MemoryType.LOCAL ); // update loop variable
 			actions.push( (Memory mem) -> {
 				mem.removeFrame();
 				mem.addFrame( old );
@@ -67,5 +68,5 @@ public abstract class ForEachLoop <T> extends CodeLine {
 		return new ControlFlow( ControlFlow.STEP_INTO );
 	}
 	
-	abstract protected List<T> list( Memory m );
+	abstract protected List<T> list( ReadOnlyMemory m );
 }

+ 7 - 6
src/codelines/ForLoop.java

@@ -5,6 +5,7 @@ import animation.ControlFlow;
 import animation.Memory;
 import animation.StackFrame;
 import animation.Memory.MemoryType;
+import animation.Memory.ReadOnlyMemory;
 import animation.StackFrame.FrameType;
 
 public abstract class ForLoop extends CodeLine {
@@ -21,10 +22,10 @@ public abstract class ForLoop extends CodeLine {
 		boolean declared = false; // prove if it is the first step in the loop
 		if( !m.isSomewhereDefined( "line_" + lineId + "_index", MemoryType.LOCAL ) )
 		{ // first loop step
-			m.declare( "line_" + lineId + "_index", minimum( m ), MemoryType.LOCAL );
+			m.declare( "line_" + lineId + "_index", minimum( m.createReadOnlyMemory() ), MemoryType.LOCAL );
 			declared = true;
 		}
-		if( m.<Integer>read( "line_" + lineId + "_index", MemoryType.LOCAL ) > maximum( m ) ) // prove if the loop has finished
+		if( m.<Integer>read( "line_" + lineId + "_index", MemoryType.LOCAL ) > maximum( m.createReadOnlyMemory() ) ) // prove if the loop has finished
 		{
 			m.undeclare( "line_" + lineId + "_index", MemoryType.LOCAL );
 			actions.push( (Memory mem) -> {});
@@ -33,7 +34,7 @@ public abstract class ForLoop extends CodeLine {
 		if( declared )
 		{
 			m.addFrame( new StackFrame( FrameType.LOOP ) );
-            m.declare( loopVar, minimum( m ), MemoryType.LOCAL ); // set loop variable
+            m.declare( loopVar, minimum( m.createReadOnlyMemory() ), MemoryType.LOCAL ); // set loop variable
 			actions.push( (Memory mem) -> {
 				mem.removeFrame();
 				mem.undeclare( "line_" + lineId + "_index", MemoryType.LOCAL );
@@ -43,7 +44,7 @@ public abstract class ForLoop extends CodeLine {
 		{
 			int oldIndex = m.<Integer>read( "line_" + lineId + "_index", MemoryType.LOCAL );
 			m.write( "line_" + lineId + "_index", oldIndex + 1, MemoryType.LOCAL ); // count index down
-			if( m.<Integer>read( "line_" + lineId + "_index", MemoryType.LOCAL ) > maximum( m ) ) // prove if loop was finished
+			if( m.<Integer>read( "line_" + lineId + "_index", MemoryType.LOCAL ) > maximum( m.createReadOnlyMemory() ) ) // prove if loop was finished
 			{
 				StackFrame sf = m.removeFrame(); // remove loop stack
 				m.undeclare( "line_" + lineId + "_index", MemoryType.LOCAL );
@@ -68,7 +69,7 @@ public abstract class ForLoop extends CodeLine {
 		return new ControlFlow( ControlFlow.STEP_INTO );
 	}
 	
-	abstract protected int minimum( Memory m );
+	abstract protected int minimum( ReadOnlyMemory m );
 	
-	abstract protected int maximum( Memory m );
+	abstract protected int maximum( ReadOnlyMemory m );
 }

+ 3 - 2
src/codelines/IfLoop.java

@@ -5,6 +5,7 @@ import animation.ControlFlow;
 import animation.Memory;
 import animation.StackFrame;
 import animation.Memory.MemoryType;
+import animation.Memory.ReadOnlyMemory;
 import animation.StackFrame.FrameType;
 
 /**
@@ -26,7 +27,7 @@ public abstract class IfLoop extends CodeLine {
 		}
 		else
 		{
-            if( condition( m ) ) {
+            if( condition( m.createReadOnlyMemory() ) ) {
             	m.addFrame( new StackFrame( FrameType.LOOP ) );
             	m.declare( "line_" + lineId + "_inside", true, MemoryType.LOCAL );
             	actions.push( (Memory mem) -> {
@@ -40,5 +41,5 @@ public abstract class IfLoop extends CodeLine {
 		}
 	}
 
-	abstract protected boolean condition( Memory m );
+	abstract protected boolean condition( ReadOnlyMemory m );
 }

+ 3 - 2
src/codelines/SetVariable.java

@@ -4,6 +4,7 @@ import animation.CodeLine;
 import animation.ControlFlow;
 import animation.Memory;
 import animation.Memory.MemoryType;
+import animation.Memory.ReadOnlyMemory;
 
 public abstract class SetVariable <T> extends CodeLine {
 
@@ -20,7 +21,7 @@ public abstract class SetVariable <T> extends CodeLine {
         
         oldExists = m.isDefined( name, MemoryType.LOCAL );
         T oldVal = m.read( name, MemoryType.LOCAL );
-        m.write( name, value( m ), MemoryType.LOCAL );
+        m.write( name, value( m.createReadOnlyMemory() ), MemoryType.LOCAL );
         actions.push( (Memory mem) -> {
             if( !oldExists )
                 mem.undeclare( name, MemoryType.LOCAL );
@@ -30,5 +31,5 @@ public abstract class SetVariable <T> extends CodeLine {
         return new ControlFlow( ControlFlow.STEP_OVER );
     }
     
-    abstract protected T value( Memory m );
+    abstract protected T value( ReadOnlyMemory m );
 }

+ 3 - 2
src/codelines/WhileLoop.java

@@ -5,6 +5,7 @@ import animation.ControlFlow;
 import animation.Memory;
 import animation.StackFrame;
 import animation.Memory.MemoryType;
+import animation.Memory.ReadOnlyMemory;
 import animation.StackFrame.FrameType;
 
 public abstract class WhileLoop extends CodeLine {
@@ -16,7 +17,7 @@ public abstract class WhileLoop extends CodeLine {
 		{ // first loop step
 			declared = true;
 		}
-        if( !condition( m ) ) // prove if loop was finished
+        if( !condition( m.createReadOnlyMemory() ) ) // prove if loop was finished
         {
             if( !declared )
             {
@@ -52,5 +53,5 @@ public abstract class WhileLoop extends CodeLine {
 		return new ControlFlow( ControlFlow.STEP_INTO );
 	}
 
-	abstract protected boolean condition( Memory m );
+	abstract protected boolean condition( ReadOnlyMemory m );
 }