mirror of
https://github.com/Stone-Red-Code/YesNt-Interpreter.git
synced 2026-09-04 09:06:41 +02:00
Rename return to end_func and add proper return statment
This commit is contained in:
@@ -43,12 +43,11 @@ YesNt is intentionally minimal and is well suited for:
|
|||||||
func greet:
|
func greet:
|
||||||
var name = %in
|
var name = %in
|
||||||
print_line Hello, ${name}!
|
print_line Hello, ${name}!
|
||||||
return
|
end_func
|
||||||
|
|
||||||
func add:
|
func add:
|
||||||
var result = %in + %in calc
|
var result = %in + %in calc
|
||||||
push_out ${result}
|
return ${result}
|
||||||
return
|
|
||||||
|
|
||||||
call greet with Alice
|
call greet with Alice
|
||||||
call greet with Bob
|
call greet with Bob
|
||||||
|
|||||||
+5
-2
@@ -26,7 +26,7 @@ var name = world
|
|||||||
func greet:
|
func greet:
|
||||||
print_line "Hello world"
|
print_line "Hello world"
|
||||||
print_line Hello ${name}
|
print_line Hello ${name}
|
||||||
return
|
end_func
|
||||||
call greet
|
call greet
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -87,7 +87,8 @@ print_line ${value}
|
|||||||
| Functions | `put value` | `push_out value` | Push out-arg in function. |
|
| Functions | `put value` | `push_out value` | Push out-arg in function. |
|
||||||
| Functions | `%out` | `%out` | Keep token name for familiarity. |
|
| Functions | `%out` | `%out` | Keep token name for familiarity. |
|
||||||
| Functions | `%iso` | `%has_out` | Inline token, bool if out arg exists. |
|
| 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. |
|
| Functions | `ccs` | `clear_call_stack` | Clear call stack. |
|
||||||
| Condition-call | `cif name \| cond` | `if cond call name` | Conditional function call. |
|
| Condition-call | `cif name \| cond` | `if cond call name` | Conditional function call. |
|
||||||
| Termination | `end` | `exit` | Planned termination. |
|
| Termination | `end` | `exit` | Planned termination. |
|
||||||
@@ -113,4 +114,6 @@ print_line ${value}
|
|||||||
|
|
||||||
- `%out` is intentionally kept as `%out`.
|
- `%out` is intentionally kept as `%out`.
|
||||||
- Postfix operations are `calc`, `eval`, and `task`.
|
- 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
@@ -38,7 +38,7 @@ print_line Hello, ${name}!
|
|||||||
func greet:
|
func greet:
|
||||||
var msg = Hello, ${name}!
|
var msg = Hello, ${name}!
|
||||||
print_line ${msg}
|
print_line ${msg}
|
||||||
return
|
end_func
|
||||||
|
|
||||||
var name = Bob
|
var name = Bob
|
||||||
call greet
|
call greet
|
||||||
|
|||||||
+1
-1
@@ -47,6 +47,6 @@ If you pass a file path, it is loaded on startup.
|
|||||||
## Formatter behavior (quick summary)
|
## Formatter behavior (quick summary)
|
||||||
|
|
||||||
- Indents `func`, `if`, `else`, and `while` blocks.
|
- 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.
|
- `exit` / `throw` / `error` close active non-function blocks for following lines.
|
||||||
- Comment lines (`# ...`) are kept unindented.
|
- Comment lines (`# ...`) are kept unindented.
|
||||||
|
|||||||
@@ -356,18 +356,18 @@ if ${debug} == True call dump_state
|
|||||||
```
|
```
|
||||||
func <name>:
|
func <name>:
|
||||||
<body>
|
<body>
|
||||||
return
|
end_func
|
||||||
```
|
```
|
||||||
|
|
||||||
A function declaration registers the function name and the line it starts on.
|
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.**
|
**Nested function declarations are not allowed.**
|
||||||
|
|
||||||
```ynt
|
```ynt
|
||||||
func add:
|
func add:
|
||||||
var result = %in + %in calc
|
var result = %in + %in calc
|
||||||
push_out ${result}
|
return ${result}
|
||||||
return
|
end_func
|
||||||
```
|
```
|
||||||
|
|
||||||
### Calling a function - `call`
|
### Calling a function - `call`
|
||||||
@@ -410,7 +410,7 @@ popped from the argument stack.
|
|||||||
func greet:
|
func greet:
|
||||||
var name = %in
|
var name = %in
|
||||||
print_line Hello, ${name}!
|
print_line Hello, ${name}!
|
||||||
return
|
end_func
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Check if input argument exists - `%has_in`
|
#### Check if input argument exists - `%has_in`
|
||||||
@@ -421,7 +421,7 @@ Only valid inside a function.
|
|||||||
```ynt
|
```ynt
|
||||||
func greet:
|
func greet:
|
||||||
if %has_in call do_greet
|
if %has_in call do_greet
|
||||||
return
|
end_func
|
||||||
```
|
```
|
||||||
|
|
||||||
### Output values
|
### Output values
|
||||||
@@ -462,6 +462,34 @@ clear_call_stack
|
|||||||
|
|
||||||
Discards all frames on the function call stack. Useful for error recovery.
|
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
|
## Lists
|
||||||
@@ -741,7 +769,7 @@ if ${x} < 0 call validate_fail
|
|||||||
|
|
||||||
func validate_fail:
|
func validate_fail:
|
||||||
throw x must not be negative
|
throw x must not be negative
|
||||||
return
|
end_func
|
||||||
```
|
```
|
||||||
|
|
||||||
### Non-fatal error - `error`
|
### 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 |
|
| `if … call` | `if cond call name` | Conditional function call |
|
||||||
| `push_in` | `push_in value` | Push input argument |
|
| `push_in` | `push_in value` | Push input argument |
|
||||||
| `push_out` | `push_out value` | Push output value (inside function) |
|
| `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 |
|
| `clear_call_stack` | `clear_call_stack` | Clear call stack |
|
||||||
| `list … new` | `list name new` | Create/reset list |
|
| `list … new` | `list name new` | Create/reset list |
|
||||||
| `list … add` | `list name add value` | Append to list |
|
| `list … add` | `list name add value` | Append to list |
|
||||||
|
|||||||
@@ -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--)
|
for (int j = blockStack.Count - 1; j >= 0; j--)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -223,4 +223,101 @@ public class FunctionStatementsTests
|
|||||||
|
|
||||||
YesNtAssert.IsLastLineEqual(lines, "outer_val");
|
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);
|
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)]
|
[Statement("return", SearchMode.Exact, SpaceAround.None, ConsoleColor.DarkYellow, ExecuteInSearchMode = true)]
|
||||||
public void Return(string _)
|
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)
|
if (!RuntimeInfo.IsInFunction)
|
||||||
{
|
{
|
||||||
@@ -153,10 +170,14 @@ internal class FunctionStatements : StatementRuntimeInformation
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
RuntimeInfo.IsInFunction = false;
|
|
||||||
|
|
||||||
if (RuntimeInfo.FunctionCallStack.Count > 0)
|
if (RuntimeInfo.FunctionCallStack.Count > 0)
|
||||||
{
|
{
|
||||||
|
if (!string.IsNullOrWhiteSpace(value))
|
||||||
|
{
|
||||||
|
RuntimeInfo.FunctionCallStack.Peek().Results.Push(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
RuntimeInfo.IsInFunction = false;
|
||||||
FunctionScope functionScope = RuntimeInfo.FunctionCallStack.Pop();
|
FunctionScope functionScope = RuntimeInfo.FunctionCallStack.Pop();
|
||||||
|
|
||||||
RuntimeInfo.OutParametersStack = new Stack<string>(functionScope.Results);
|
RuntimeInfo.OutParametersStack = new Stack<string>(functionScope.Results);
|
||||||
|
|||||||
Reference in New Issue
Block a user