Make end_func the only func ending block

This commit is contained in:
Stone_Red
2026-08-07 01:03:00 +02:00
parent 6bc5d01a2e
commit a5f9c5a178
6 changed files with 93 additions and 12 deletions
+2 -1
View File
@@ -47,6 +47,7 @@ If you pass a file path, it is loaded on startup.
## Formatter behavior (quick summary)
- Indents `func`, `if`, `else`, and `while` blocks.
- Dedents on `return`, `end_func`, `end_if`, and `end_while`.
- Dedents on `end_func`, `end_if`, and `end_while`.
- `return` / `return <value>` are regular body statements and stay indented with the block they are in.
- `exit` / `throw` / `error` close active non-function blocks for following lines.
- Comment lines (`# ...`) are kept unindented.
+3 -7
View File
@@ -261,15 +261,11 @@ internal class TextEditor
}
}
}
else if (trimmed == "return" || trimmed == "end_func" || trimmed.StartsWith("return ", StringComparison.Ordinal))
else if (trimmed == "end_func")
{
for (int j = blockStack.Count - 1; j >= 0; j--)
if (blockStack.Count > 0 && blockStack[^1] == "func")
{
if (blockStack[j] == "func")
{
blockStack.RemoveAt(j);
break;
}
blockStack.RemoveAt(blockStack.Count - 1);
}
}
@@ -16,6 +16,7 @@ public class CodeFlowTests
"func yes:",
"global result = 1",
"return",
"end_func",
"${result}"
];
YesNtAssert.IsLastLineEqual(lines, "1");
@@ -193,6 +194,7 @@ public class CodeFlowTests
"func set_result:",
"global result = ok",
"return",
"end_func",
"if 1 == 1 call set_result",
"${result}"
];
@@ -124,9 +124,13 @@ public class FunctionStatementsTests
{
List<string> lines =
[
"goto main",
"func outer:",
"func inner:",
"return"
"return",
"end_func",
"label main:",
"call outer"
];
YesNtAssert.ContainsTerminationMessage(lines, "Nested functions are not allowed");
@@ -414,10 +418,64 @@ public class FunctionStatementsTests
"call add with 3, 4",
"func add: a, b",
"return ${a} + ${b} calc",
"end_func",
"var total = %out",
"${total}"
];
YesNtAssert.IsLastLineEqual(lines, "7");
}
// --- Top-down function body skip tests ---
[TestMethod]
public void FunctionDeclaredFirstThenCalledTest()
{
List<string> lines =
[
"func add: a, b",
"return ${a} + ${b} calc",
"end_func",
"call add with 3, 7",
"var total = %out",
"${total}"
];
YesNtAssert.IsLastLineEqual(lines, "10");
}
[TestMethod]
public void FunctionBodyWithNestedReturnSkippedTest()
{
List<string> lines =
[
"func test: a, b",
"if ${a} == ${b}:",
"print_line %in",
"return 999",
"end_if",
"return ${a} + ${b} calc",
"end_func",
"call test with 1, 2, 4",
"var value = %out",
"${value}"
];
YesNtAssert.IsLastLineEqual(lines, "3");
}
[TestMethod]
public void FunctionWithoutEndFuncFailsTest()
{
List<string> lines =
[
"func answer:",
"return 42",
"call answer",
"var value = %out",
"${value}"
];
YesNtAssert.ContainsTerminationMessage(lines, "no matching \"end_func\"");
}
}
@@ -36,6 +36,11 @@ internal static class ExitMessages
return $"Function \"{function}\" not found";
}
internal static string FunctionWithoutEndFunc(string function)
{
return $"Function \"{function}\" has no matching \"end_func\"";
}
internal static string VariableNotFound(string variable)
{
return $"Variable \"{variable}\" not found";
@@ -10,7 +10,7 @@ namespace YesNt.Interpreter.Statements;
internal class FunctionStatements : StatementRuntimeInformation
{
[Statement("func", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.DarkYellow, ExecuteInSearchMode = true, Separator = ":")]
[Statement("func", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.DarkYellow, ExecuteInSearchMode = true, Separator = ":", BlockPair = "end_func")]
public void FindFunction(string args)
{
if (RuntimeInfo.InternalIsInFunction)
@@ -32,7 +32,26 @@ internal class FunctionStatements : StatementRuntimeInformation
RuntimeInfo.SearchFunction = string.Empty;
}
RuntimeInfo.IsInFunction = true;
bool isDefinitionScan = RuntimeInfo.FunctionCallStack.Count == 0
&& string.IsNullOrEmpty(RuntimeInfo.SearchFunction)
&& string.IsNullOrEmpty(RuntimeInfo.SearchLabel);
if (isDefinitionScan)
{
if (RuntimeInfo.BlockBoundaries.TryGetValue(RuntimeInfo.LineNumber, out int endLine) && endLine > RuntimeInfo.LineNumber)
{
RuntimeInfo.IsInFunction = false;
RuntimeInfo.LineNumber = endLine;
}
else
{
RuntimeInfo.Exit(ExitMessages.FunctionWithoutEndFunc(key), true);
}
}
else
{
RuntimeInfo.IsInFunction = true;
}
}
[Statement("push_in", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.Yellow)]
@@ -126,7 +145,7 @@ internal class FunctionStatements : StatementRuntimeInformation
RuntimeInfo.FunctionCallStack.Peek().Results.Push(args);
}
[Statement("end_func", SearchMode.Exact, SpaceAround.None, ConsoleColor.DarkYellow, ExecuteInSearchMode = true)]
[Statement("end_func", SearchMode.Exact, SpaceAround.None, ConsoleColor.DarkYellow, ExecuteInSearchMode = true, IsBlockEnd = true)]
public void EndFunction(string _)
{
HandleReturn(string.Empty);