Rename return to end_func and add proper return statment

This commit is contained in:
Stone_Red
2026-08-06 20:36:32 +02:00
parent ade4ab5ea6
commit e7bf9591ba
8 changed files with 167 additions and 18 deletions
+2 -3
View File
@@ -43,12 +43,11 @@ YesNt is intentionally minimal and is well suited for:
func greet:
var name = %in
print_line Hello, ${name}!
return
end_func
func add:
var result = %in + %in calc
push_out ${result}
return
return ${result}
call greet with Alice
call greet with Bob
+5 -2
View File
@@ -26,7 +26,7 @@ var name = world
func greet:
print_line "Hello world"
print_line Hello ${name}
return
end_func
call greet
```
@@ -87,7 +87,8 @@ print_line ${value}
| Functions | `put value` | `push_out value` | Push out-arg in function. |
| Functions | `%out` | `%out` | Keep token name for familiarity. |
| Functions | `%iso` | `%has_out` | Inline token, bool if out arg exists. |
| Functions | `ret` | `return` | Return from function. |
| Functions | `ret` | `end_func` | Return from function. |
| Functions | `return value` | `return value` | Return from function, optionally pushing a value to the out stack. |
| Functions | `ccs` | `clear_call_stack` | Clear call stack. |
| Condition-call | `cif name \| cond` | `if cond call name` | Conditional function call. |
| Termination | `end` | `exit` | Planned termination. |
@@ -113,4 +114,6 @@ print_line ${value}
- `%out` is intentionally kept as `%out`.
- Postfix operations are `calc`, `eval`, and `task`.
- `return` exits the function early (optionally with a value via `return <value>`);
`end_func` is the explicit end-of-function marker. Both terminate the current function call.
+1 -1
View File
@@ -38,7 +38,7 @@ print_line Hello, ${name}!
func greet:
var msg = Hello, ${name}!
print_line ${msg}
return
end_func
var name = Bob
call greet
+1 -1
View File
@@ -47,6 +47,6 @@ 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_if`, and `end_while`.
- Dedents on `return`, `end_func`, `end_if`, and `end_while`.
- `exit` / `throw` / `error` close active non-function blocks for following lines.
- Comment lines (`# ...`) are kept unindented.
+37 -8
View File
@@ -356,18 +356,18 @@ if ${debug} == True call dump_state
```
func <name>:
<body>
return
end_func
```
A function declaration registers the function name and the line it starts on.
The body runs until `return` is reached.
The body runs until `end_func` (or an early `return`) is reached.
**Nested function declarations are not allowed.**
```ynt
func add:
var result = %in + %in calc
push_out ${result}
return
return ${result}
end_func
```
### Calling a function - `call`
@@ -410,7 +410,7 @@ popped from the argument stack.
func greet:
var name = %in
print_line Hello, ${name}!
return
end_func
```
#### Check if input argument exists - `%has_in`
@@ -421,7 +421,7 @@ Only valid inside a function.
```ynt
func greet:
if %has_in call do_greet
return
end_func
```
### Output values
@@ -462,6 +462,34 @@ clear_call_stack
Discards all frames on the function call stack. Useful for error recovery.
### Return from a function - `end_func` and `return`
```
end_func
return
return <value>
```
`end_func` and a bare `return` end the current function call and hand control back to the caller.
`return <value>` does the same but first pushes `<value>` onto the output stack
(it is equivalent to `push_out <value>` followed by `end_func`), so the caller can read it with `%out`.
`return` may be used anywhere in the body to exit a function early.
```ynt
func add:
var a = %in
var b = %in
if ${a} == 0:
return 0
end_if
return ${a} + ${b} calc
call add with 0, 5
var total = %out
print_line ${total}
```
Only valid inside a function; otherwise the script terminates with an error.
---
## Lists
@@ -741,7 +769,7 @@ if ${x} < 0 call validate_fail
func validate_fail:
throw x must not be negative
return
end_func
```
### Non-fatal error - `error`
@@ -778,7 +806,8 @@ Like `throw` but does **not** cancel background tasks.
| `if … call` | `if cond call name` | Conditional function call |
| `push_in` | `push_in value` | Push input argument |
| `push_out` | `push_out value` | Push output value (inside function) |
| `return` | `return` | Return from function |
| `end_func` | `end_func` | End current function |
| `return` | `return value` | Return from function (optional value via output stack) |
| `clear_call_stack` | `clear_call_stack` | Clear call stack |
| `list … new` | `list name new` | Create/reset list |
| `list … add` | `list name add value` | Append to list |
+1 -1
View File
@@ -261,7 +261,7 @@ internal class TextEditor
}
}
}
else if (trimmed == "return")
else if (trimmed == "return" || trimmed == "end_func" || trimmed.StartsWith("return ", StringComparison.Ordinal))
{
for (int j = blockStack.Count - 1; j >= 0; j--)
{
@@ -223,4 +223,101 @@ public class FunctionStatementsTests
YesNtAssert.IsLastLineEqual(lines, "outer_val");
}
// --- end_func / return value tests ---
[TestMethod]
public void EndFuncReturnsToCallerTest()
{
List<string> lines =
[
"goto main",
"func greet:",
"global result = done",
"end_func",
"label main:",
"call greet",
"${result}"
];
YesNtAssert.IsLastLineEqual(lines, "done");
}
[TestMethod]
public void ReturnWithValueTest()
{
List<string> lines =
[
"goto main",
"func add:",
"var a = %in",
"var b = %in",
"var sum = ${a} + ${b} calc",
"return ${sum}",
"label main:",
"call add with 3, 4",
"var total = %out",
"${total}"
];
YesNtAssert.IsLastLineEqual(lines, "7");
}
[TestMethod]
public void ReturnWithLiteralValueTest()
{
List<string> lines =
[
"goto main",
"func make:",
"return out_value",
"label main:",
"call make",
"var value = %out",
"${value}"
];
YesNtAssert.IsLastLineEqual(lines, "out_value");
}
[TestMethod]
public void ReturnEarlyExitSkipsRestOfFunctionTest()
{
List<string> lines =
[
"goto main",
"func probe:",
"push_out should_not_escape",
"return",
"push_out should_never_run",
"label main:",
"call probe",
"var value = %out",
"${value}"
];
YesNtAssert.IsLastLineEqual(lines, "should_not_escape");
}
[TestMethod]
public void ReturnWithValueOutsideFunctionFailsTest()
{
List<string> lines =
[
"return 42"
];
YesNtAssert.ContainsTerminationMessage(lines, "Statement not allowed outside of function");
}
[TestMethod]
public void EndFuncOutsideFunctionFailsTest()
{
List<string> lines =
[
"end_func"
];
YesNtAssert.ContainsTerminationMessage(lines, "Statement not allowed outside of function");
}
}
@@ -133,8 +133,25 @@ internal class FunctionStatements : StatementRuntimeInformation
RuntimeInfo.FunctionCallStack.Peek().Results.Push(args);
}
[Statement("end_func", SearchMode.Exact, SpaceAround.None, ConsoleColor.DarkYellow, ExecuteInSearchMode = true)]
public void EndFunction(string _)
{
HandleReturn(string.Empty);
}
[Statement("return", SearchMode.Exact, SpaceAround.None, ConsoleColor.DarkYellow, ExecuteInSearchMode = true)]
public void Return(string _)
{
HandleReturn(string.Empty);
}
[Statement("return", SearchMode.StartOfLine, SpaceAround.End, ConsoleColor.DarkYellow, ExecuteInSearchMode = true)]
public void ReturnWithValue(string args)
{
HandleReturn(args.Trim());
}
private void HandleReturn(string value)
{
if (!RuntimeInfo.IsInFunction)
{
@@ -153,10 +170,14 @@ internal class FunctionStatements : StatementRuntimeInformation
return;
}
RuntimeInfo.IsInFunction = false;
if (RuntimeInfo.FunctionCallStack.Count > 0)
{
if (!string.IsNullOrWhiteSpace(value))
{
RuntimeInfo.FunctionCallStack.Peek().Results.Push(value);
}
RuntimeInfo.IsInFunction = false;
FunctionScope functionScope = RuntimeInfo.FunctionCallStack.Pop();
RuntimeInfo.OutParametersStack = new Stack<string>(functionScope.Results);