mirror of
https://github.com/Stone-Red-Code/YesNt-Interpreter.git
synced 2026-09-09 16:06:08 +02:00
Add support for block-style if/else and while loop statements with tests
This commit is contained in:
+20
-12
@@ -19,18 +19,6 @@ This document describes the current, word-based YesNt syntax.
|
|||||||
|
|
||||||
## Quick Example
|
## Quick Example
|
||||||
|
|
||||||
v1:
|
|
||||||
|
|
||||||
```ynt
|
|
||||||
<name = world
|
|
||||||
fnc greet
|
|
||||||
cwl Hello >name
|
|
||||||
ret
|
|
||||||
cal greet
|
|
||||||
```
|
|
||||||
|
|
||||||
v2:
|
|
||||||
|
|
||||||
```ynt
|
```ynt
|
||||||
let name = world
|
let name = world
|
||||||
func greet:
|
func greet:
|
||||||
@@ -39,6 +27,26 @@ return
|
|||||||
call greet
|
call greet
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Block Conditionals
|
||||||
|
|
||||||
|
```ynt
|
||||||
|
if 10 > 5:
|
||||||
|
print_line yes
|
||||||
|
else:
|
||||||
|
print_line no
|
||||||
|
end_if
|
||||||
|
```
|
||||||
|
|
||||||
|
## While Loops
|
||||||
|
|
||||||
|
```ynt
|
||||||
|
let i = 3
|
||||||
|
while ${i} > 0:
|
||||||
|
print_line ${i}
|
||||||
|
let i = ${i} - 1 calc
|
||||||
|
end_while
|
||||||
|
```
|
||||||
|
|
||||||
## Full v1 -> v2 Mapping
|
## Full v1 -> v2 Mapping
|
||||||
|
|
||||||
| Area | v1 Syntax | v2 Syntax | Notes |
|
| Area | v1 Syntax | v2 Syntax | Notes |
|
||||||
|
|||||||
@@ -34,4 +34,106 @@ public class CodeFlowTests
|
|||||||
];
|
];
|
||||||
YesNtAssert.IsLastLineEqual(lines, "1");
|
YesNtAssert.IsLastLineEqual(lines, "1");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void IfBlockTrueTest()
|
||||||
|
{
|
||||||
|
List<string> lines =
|
||||||
|
[
|
||||||
|
"let result = low",
|
||||||
|
"if 6 > 5:",
|
||||||
|
"let result = high",
|
||||||
|
"end_if",
|
||||||
|
"${result}"
|
||||||
|
];
|
||||||
|
|
||||||
|
YesNtAssert.IsLastLineEqual(lines, "high");
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void IfElseFalseBranchTest()
|
||||||
|
{
|
||||||
|
List<string> lines =
|
||||||
|
[
|
||||||
|
"let result = low",
|
||||||
|
"if 6 < 5:",
|
||||||
|
"let result = high",
|
||||||
|
"else:",
|
||||||
|
"let result = medium",
|
||||||
|
"end_if",
|
||||||
|
"${result}"
|
||||||
|
];
|
||||||
|
|
||||||
|
YesNtAssert.IsLastLineEqual(lines, "medium");
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void NestedIfElseTest()
|
||||||
|
{
|
||||||
|
List<string> lines =
|
||||||
|
[
|
||||||
|
"let result = 0",
|
||||||
|
"if 1 == 1:",
|
||||||
|
"if 2 == 3:",
|
||||||
|
"let result = 1",
|
||||||
|
"else:",
|
||||||
|
"let result = 2",
|
||||||
|
"end_if",
|
||||||
|
"end_if",
|
||||||
|
"${result}"
|
||||||
|
];
|
||||||
|
|
||||||
|
YesNtAssert.IsLastLineEqual(lines, "2");
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void WhileLoopTest()
|
||||||
|
{
|
||||||
|
List<string> lines =
|
||||||
|
[
|
||||||
|
"let i = 3",
|
||||||
|
"while ${i} > 0:",
|
||||||
|
"let i = ${i} - 1 calc",
|
||||||
|
"end_while",
|
||||||
|
"${i}"
|
||||||
|
];
|
||||||
|
|
||||||
|
YesNtAssert.IsLastLineEqual(lines, "0");
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void WhileSkipBodyWhenFalseTest()
|
||||||
|
{
|
||||||
|
List<string> lines =
|
||||||
|
[
|
||||||
|
"let i = 0",
|
||||||
|
"while ${i} > 0:",
|
||||||
|
"let i = 99",
|
||||||
|
"end_while",
|
||||||
|
"${i}"
|
||||||
|
];
|
||||||
|
|
||||||
|
YesNtAssert.IsLastLineEqual(lines, "0");
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void NestedWhileLoopTest()
|
||||||
|
{
|
||||||
|
List<string> lines =
|
||||||
|
[
|
||||||
|
"let outer = 2",
|
||||||
|
"let count = 0",
|
||||||
|
"while ${outer} > 0:",
|
||||||
|
"let inner = 2",
|
||||||
|
"while ${inner} > 0:",
|
||||||
|
"let count = ${count} + 1 calc",
|
||||||
|
"let inner = ${inner} - 1 calc",
|
||||||
|
"end_while",
|
||||||
|
"let outer = ${outer} - 1 calc",
|
||||||
|
"end_while",
|
||||||
|
"${count}"
|
||||||
|
];
|
||||||
|
|
||||||
|
YesNtAssert.IsLastLineEqual(lines, "4");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -140,6 +140,105 @@ internal class CodeFlowStatements : StatementRuntimeInformation
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Statement("if", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.Green, Priority = Priority.VeryLow, Separator = ":")]
|
||||||
|
public void IfBlock(string args)
|
||||||
|
{
|
||||||
|
args = args.Trim();
|
||||||
|
if (!args.EndsWith(':'))
|
||||||
|
{
|
||||||
|
RuntimeInfo.Exit("Invalid syntax", true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
string condition = args[..^1].Trim();
|
||||||
|
bool? result = Evaluator.EvaluateCondition(condition);
|
||||||
|
|
||||||
|
if (result is null)
|
||||||
|
{
|
||||||
|
RuntimeInfo.Exit("Invalid operation", true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result == true)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
(int targetLine, _) = FindElseOrEndIf(RuntimeInfo.LineNumber);
|
||||||
|
if (targetLine < 0)
|
||||||
|
{
|
||||||
|
RuntimeInfo.Exit("No matching end_if found", true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
RuntimeInfo.LineNumber = targetLine;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Statement("else:", SearchMode.Exact, SpaceAround.None, ConsoleColor.Green)]
|
||||||
|
public void Else(string _)
|
||||||
|
{
|
||||||
|
int targetLine = FindEndIf(RuntimeInfo.LineNumber);
|
||||||
|
if (targetLine < 0)
|
||||||
|
{
|
||||||
|
RuntimeInfo.Exit("No matching end_if found", true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
RuntimeInfo.LineNumber = targetLine;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Statement("end_if", SearchMode.Exact, SpaceAround.None, ConsoleColor.Green)]
|
||||||
|
public void EndIf(string _)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
[Statement("while", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.Green, Priority = Priority.VeryLow, Separator = ":")]
|
||||||
|
public void While(string args)
|
||||||
|
{
|
||||||
|
args = args.Trim();
|
||||||
|
if (!args.EndsWith(':'))
|
||||||
|
{
|
||||||
|
RuntimeInfo.Exit("Invalid syntax", true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
string condition = args[..^1].Trim();
|
||||||
|
bool? result = Evaluator.EvaluateCondition(condition);
|
||||||
|
|
||||||
|
if (result is null)
|
||||||
|
{
|
||||||
|
RuntimeInfo.Exit("Invalid operation", true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result == true)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int endWhileLine = FindEndWhile(RuntimeInfo.LineNumber);
|
||||||
|
if (endWhileLine < 0)
|
||||||
|
{
|
||||||
|
RuntimeInfo.Exit("No matching end_while found", true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
RuntimeInfo.LineNumber = endWhileLine;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Statement("end_while", SearchMode.Exact, SpaceAround.None, ConsoleColor.Green)]
|
||||||
|
public void EndWhile(string _)
|
||||||
|
{
|
||||||
|
int whileLine = FindWhile(RuntimeInfo.LineNumber);
|
||||||
|
if (whileLine < 0)
|
||||||
|
{
|
||||||
|
RuntimeInfo.Exit("No matching while found", true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
RuntimeInfo.LineNumber = whileLine - 1;
|
||||||
|
}
|
||||||
|
|
||||||
[Statement("exit", SearchMode.Exact, SpaceAround.None, ConsoleColor.Red, ExecuteInSearchMode = true)]
|
[Statement("exit", SearchMode.Exact, SpaceAround.None, ConsoleColor.Red, ExecuteInSearchMode = true)]
|
||||||
public void End(string _)
|
public void End(string _)
|
||||||
{
|
{
|
||||||
@@ -198,4 +297,132 @@ internal class CodeFlowStatements : StatementRuntimeInformation
|
|||||||
{
|
{
|
||||||
return value.Trim().TrimEnd(':').Trim();
|
return value.Trim().TrimEnd(':').Trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private (int TargetLine, bool IsElse) FindElseOrEndIf(int currentLine)
|
||||||
|
{
|
||||||
|
int depth = 0;
|
||||||
|
|
||||||
|
for (int i = currentLine + 1; i < RuntimeInfo.Lines.Count; i++)
|
||||||
|
{
|
||||||
|
string line = RuntimeInfo.Lines[i].Content.Trim().Replace("\r", string.Empty);
|
||||||
|
|
||||||
|
if (IsIfStart(line))
|
||||||
|
{
|
||||||
|
depth++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line == "end_if")
|
||||||
|
{
|
||||||
|
if (depth == 0)
|
||||||
|
{
|
||||||
|
return (i, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
depth--;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line == "else:" && depth == 0)
|
||||||
|
{
|
||||||
|
return (i, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (-1, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int FindEndIf(int currentLine)
|
||||||
|
{
|
||||||
|
int depth = 0;
|
||||||
|
|
||||||
|
for (int i = currentLine + 1; i < RuntimeInfo.Lines.Count; i++)
|
||||||
|
{
|
||||||
|
string line = RuntimeInfo.Lines[i].Content.Trim().Replace("\r", string.Empty);
|
||||||
|
|
||||||
|
if (IsIfStart(line))
|
||||||
|
{
|
||||||
|
depth++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line == "end_if")
|
||||||
|
{
|
||||||
|
if (depth == 0)
|
||||||
|
{
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
depth--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsIfStart(string line)
|
||||||
|
{
|
||||||
|
return line.StartsWith("if ", StringComparison.Ordinal) && line.EndsWith(':');
|
||||||
|
}
|
||||||
|
|
||||||
|
private int FindEndWhile(int currentLine)
|
||||||
|
{
|
||||||
|
int depth = 0;
|
||||||
|
|
||||||
|
for (int i = currentLine + 1; i < RuntimeInfo.Lines.Count; i++)
|
||||||
|
{
|
||||||
|
string line = RuntimeInfo.Lines[i].Content.Trim().Replace("\r", string.Empty);
|
||||||
|
|
||||||
|
if (IsWhileStart(line))
|
||||||
|
{
|
||||||
|
depth++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line == "end_while")
|
||||||
|
{
|
||||||
|
if (depth == 0)
|
||||||
|
{
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
depth--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int FindWhile(int currentLine)
|
||||||
|
{
|
||||||
|
int depth = 0;
|
||||||
|
|
||||||
|
for (int i = currentLine - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
string line = RuntimeInfo.Lines[i].Content.Trim().Replace("\r", string.Empty);
|
||||||
|
|
||||||
|
if (line == "end_while")
|
||||||
|
{
|
||||||
|
depth++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsWhileStart(line))
|
||||||
|
{
|
||||||
|
if (depth == 0)
|
||||||
|
{
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
depth--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsWhileStart(string line)
|
||||||
|
{
|
||||||
|
return line.StartsWith("while ", StringComparison.Ordinal) && line.EndsWith(':');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user