diff --git a/.gitignore b/.gitignore
index 65181f1..73d612b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -212,3 +212,4 @@ GeneratedArtifacts/
_Pvt_Extensions/
ModelManifest.xml
/IronBlock.Runner/MyExample.xml
+test_output.txt
diff --git a/IronBlock.Tests/ControlsTests.cs b/IronBlock.Tests/ControlsTests.cs
index cabfc56..668c367 100644
--- a/IronBlock.Tests/ControlsTests.cs
+++ b/IronBlock.Tests/ControlsTests.cs
@@ -330,5 +330,717 @@ public void Test_Controls_For()
}
+ [TestMethod]
+ public void Test_Controls_For_Break()
+ {
+ const string xml = @"
+
+
+ i
+
+
+ i
+
+
+ 1
+
+
+
+
+ 5
+
+
+
+
+ 1
+
+
+
+
+
+
+ i
+
+
+
+
+
+
+ EQ
+
+
+ i
+
+
+
+
+ 3
+
+
+
+
+
+
+ BREAK
+
+
+
+
+
+
+
+
+";
+ new Parser()
+ .AddStandardBlocks()
+ .AddDebugPrinter()
+ .Parse(xml)
+ .Evaluate();
+
+ Assert.AreEqual("1,2,3", string.Join(",", TestExtensions.GetDebugText()));
+ }
+
+
+ [TestMethod]
+ public void Test_Controls_For_Continue()
+ {
+ const string xml = @"
+
+
+ i
+
+
+ i
+
+
+ 1
+
+
+
+
+ 5
+
+
+
+
+ 1
+
+
+
+
+
+
+ EQ
+
+
+ i
+
+
+
+
+ 3
+
+
+
+
+
+
+ CONTINUE
+
+
+
+
+
+
+ i
+
+
+
+
+
+
+
+
+";
+ new Parser()
+ .AddStandardBlocks()
+ .AddDebugPrinter()
+ .Parse(xml)
+ .Evaluate();
+
+ Assert.AreEqual("1,2,4,5", string.Join(",", TestExtensions.GetDebugText()));
+ }
+
+
+ [TestMethod]
+ public void Test_Controls_ForEach_Break()
+ {
+ const string xml = @"
+
+
+ i
+
+
+ i
+
+
+
+ SPLIT
+
+
+ a,b,c,d,e
+
+
+
+
+ ,
+
+
+
+
+
+
+
+
+ i
+
+
+
+
+
+
+ EQ
+
+
+ i
+
+
+
+
+ c
+
+
+
+
+
+
+ BREAK
+
+
+
+
+
+
+
+
+";
+ new Parser()
+ .AddStandardBlocks()
+ .AddDebugPrinter()
+ .Parse(xml)
+ .Evaluate();
+
+ Assert.AreEqual("a,b,c", string.Join(",", TestExtensions.GetDebugText()));
+ }
+
+
+ [TestMethod]
+ public void Test_Controls_ForEach_Continue()
+ {
+ const string xml = @"
+
+
+ i
+
+
+ i
+
+
+
+ SPLIT
+
+
+ a,b,c,d,e
+
+
+
+
+ ,
+
+
+
+
+
+
+
+
+ EQ
+
+
+ i
+
+
+
+
+ c
+
+
+
+
+
+
+ CONTINUE
+
+
+
+
+
+
+ i
+
+
+
+
+
+
+
+
+";
+ new Parser()
+ .AddStandardBlocks()
+ .AddDebugPrinter()
+ .Parse(xml)
+ .Evaluate();
+
+ Assert.AreEqual("a,b,d,e", string.Join(",", TestExtensions.GetDebugText()));
+ }
+
+
+ [TestMethod]
+ public void Test_Controls_While_Continue()
+ {
+ const string xml = @"
+
+
+ x
+
+
+ x
+
+
+ 0
+
+
+
+
+ WHILE
+
+
+ LT
+
+
+ x
+
+
+
+
+ 5
+
+
+
+
+
+
+ x
+
+
+ ADD
+
+
+ x
+
+
+
+
+ 1
+
+
+
+
+
+
+
+
+ EQ
+
+
+ x
+
+
+
+
+ 3
+
+
+
+
+
+
+ CONTINUE
+
+
+
+
+
+
+ x
+
+
+
+
+
+
+
+
+
+
+
+
+";
+ new Parser()
+ .AddStandardBlocks()
+ .AddDebugPrinter()
+ .Parse(xml)
+ .Evaluate();
+
+ Assert.AreEqual("1,2,4,5", string.Join(",", TestExtensions.GetDebugText()));
+ }
+
+
+ [TestMethod]
+ public void Test_Controls_Until_Break()
+ {
+ const string xml = @"
+
+
+ x
+
+
+ x
+
+
+ 0
+
+
+
+
+ UNTIL
+
+
+ GT
+
+
+ x
+
+
+
+
+ 10
+
+
+
+
+
+
+ x
+
+
+ ADD
+
+
+ x
+
+
+
+
+ 1
+
+
+
+
+
+
+
+
+ x
+
+
+
+
+
+
+ EQ
+
+
+ x
+
+
+
+
+ 3
+
+
+
+
+
+
+ BREAK
+
+
+
+
+
+
+
+
+
+
+
+
+";
+ new Parser()
+ .AddStandardBlocks()
+ .AddDebugPrinter()
+ .Parse(xml)
+ .Evaluate();
+
+ Assert.AreEqual("1,2,3", string.Join(",", TestExtensions.GetDebugText()));
+ }
+
+
+ [TestMethod]
+ public void Test_Controls_Until_Continue()
+ {
+ const string xml = @"
+
+
+ x
+
+
+ x
+
+
+ 0
+
+
+
+
+ UNTIL
+
+
+ GT
+
+
+ x
+
+
+
+
+ 5
+
+
+
+
+
+
+ x
+
+
+ ADD
+
+
+ x
+
+
+
+
+ 1
+
+
+
+
+
+
+
+
+ EQ
+
+
+ x
+
+
+
+
+ 3
+
+
+
+
+
+
+ CONTINUE
+
+
+
+
+
+
+ x
+
+
+
+
+
+
+
+
+
+
+
+
+";
+ new Parser()
+ .AddStandardBlocks()
+ .AddDebugPrinter()
+ .Parse(xml)
+ .Evaluate();
+
+ Assert.AreEqual("1,2,4,5,6", string.Join(",", TestExtensions.GetDebugText()));
+ }
+
+
+ [TestMethod]
+ public void Test_Controls_Nested_Loops_EscapeMode_Isolation()
+ {
+ const string xml = @"
+
+
+ i
+ j
+
+
+ i
+
+
+ 1
+
+
+
+
+ 3
+
+
+
+
+ 1
+
+
+
+
+ j
+
+
+ 1
+
+
+
+
+ 3
+
+
+
+
+ 1
+
+
+
+
+
+
+ EQ
+
+
+ j
+
+
+
+
+ 2
+
+
+
+
+
+
+ BREAK
+
+
+
+
+
+
+
+
+
+ i
+
+
+
+
+ j
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ outer:
+
+
+
+
+ i
+
+
+
+
+
+
+
+
+
+
+";
+ new Parser()
+ .AddStandardBlocks()
+ .AddDebugPrinter()
+ .Parse(xml)
+ .Evaluate();
+
+ // Inner loop breaks at j=2, but outer loop continues
+ // For each i (1,2,3), inner prints j=1 only, then outer prints "outer:i"
+ Assert.AreEqual("11,outer:1,21,outer:2,31,outer:3", string.Join(",", TestExtensions.GetDebugText()));
+ }
+
+
}
}
diff --git a/IronBlock/Blocks/Controls/ControlsFor.cs b/IronBlock/Blocks/Controls/ControlsFor.cs
index 46e8085..8809fee 100644
--- a/IronBlock/Blocks/Controls/ControlsFor.cs
+++ b/IronBlock/Blocks/Controls/ControlsFor.cs
@@ -37,6 +37,20 @@ public override object Evaluate(Context context)
return context.ReturnValue;
}
statement.Evaluate(context);
+
+ if (context.EscapeMode == EscapeMode.Break)
+ {
+ context.EscapeMode = EscapeMode.None;
+ break;
+ }
+
+ if (context.EscapeMode == EscapeMode.Continue)
+ {
+ context.EscapeMode = EscapeMode.None;
+ context.Variables[variableName] = (double)context.Variables[variableName] + byValue;
+ continue;
+ }
+
if (context.EscapeMode == EscapeMode.Return)
{
return context.ReturnValue;
diff --git a/IronBlock/Blocks/Controls/ControlsForEach.cs b/IronBlock/Blocks/Controls/ControlsForEach.cs
index a99cdcf..e26897c 100644
--- a/IronBlock/Blocks/Controls/ControlsForEach.cs
+++ b/IronBlock/Blocks/Controls/ControlsForEach.cs
@@ -32,6 +32,19 @@ public override object Evaluate(Context context)
context.Variables.Add(variableName, item);
}
statement.Evaluate(context);
+
+ if (context.EscapeMode == EscapeMode.Break)
+ {
+ context.EscapeMode = EscapeMode.None;
+ break;
+ }
+
+ if (context.EscapeMode == EscapeMode.Continue)
+ {
+ context.EscapeMode = EscapeMode.None;
+ continue;
+ }
+
if (context.EscapeMode == EscapeMode.Return)
{
return context.ReturnValue;
diff --git a/IronBlock/Blocks/Controls/ControlsWhileUntil.cs b/IronBlock/Blocks/Controls/ControlsWhileUntil.cs
index 1ada31f..c6a487a 100644
--- a/IronBlock/Blocks/Controls/ControlsWhileUntil.cs
+++ b/IronBlock/Blocks/Controls/ControlsWhileUntil.cs
@@ -22,16 +22,24 @@ public override object Evaluate(Context context)
{
while ((bool)value.Evaluate(context))
{
+ if (context.EscapeMode == EscapeMode.Return)
+ {
+ return context.ReturnValue;
+ }
+ statement.Evaluate(context);
+
if (context.EscapeMode == EscapeMode.Break)
{
context.EscapeMode = EscapeMode.None;
break;
}
- if (context.EscapeMode == EscapeMode.Return)
+
+ if (context.EscapeMode == EscapeMode.Continue)
{
- return context.ReturnValue;
+ context.EscapeMode = EscapeMode.None;
+ continue;
}
- statement.Evaluate(context);
+
if (context.EscapeMode == EscapeMode.Return)
{
return context.ReturnValue;
@@ -47,6 +55,19 @@ public override object Evaluate(Context context)
return context.ReturnValue;
}
statement.Evaluate(context);
+
+ if (context.EscapeMode == EscapeMode.Break)
+ {
+ context.EscapeMode = EscapeMode.None;
+ break;
+ }
+
+ if (context.EscapeMode == EscapeMode.Continue)
+ {
+ context.EscapeMode = EscapeMode.None;
+ continue;
+ }
+
if (context.EscapeMode == EscapeMode.Return)
{
return context.ReturnValue;