mirror of
https://github.com/Stone-Red-Code/YesNt-Interpreter.git
synced 2026-09-04 00:56:31 +02:00
Add proper docs
This commit is contained in:
@@ -2,11 +2,16 @@
|
||||
|
||||
> YesNt is a imperative and interpreted language inspired by the Assembly language.
|
||||
|
||||
## Syntax
|
||||
## Documentation
|
||||
|
||||
Current language syntax is documented in [SYNTAX_V2.md](SYNTAX_V2.md).
|
||||
| Document | Description |
|
||||
| -------------------------------------------------------- | ----------------------------------------- |
|
||||
| [docs/README.md](docs/README.md) | Getting started |
|
||||
| [docs/language-reference.md](docs/language-reference.md) | Full language reference |
|
||||
| [docs/library-api.md](docs/library-api.md) | Embedding the interpreter as a C# library |
|
||||
| [docs/editor.md](docs/editor.md) | Using the terminal code editor |
|
||||
|
||||
Example:
|
||||
## Quick example
|
||||
|
||||
```ynt
|
||||
var name = world
|
||||
@@ -16,6 +21,5 @@ print_line Hello ${name}
|
||||
## Run
|
||||
|
||||
```bash
|
||||
dotnet run --project YesNt.Interpreter -- path/to/script.ynt
|
||||
dotnet run --project YesNt.Interpreter.App -- path/to/script.ynt
|
||||
```
|
||||
|
||||
|
||||
@@ -48,6 +48,14 @@ internal class InputHandler(TextEditor textEditor)
|
||||
textEditor.CursorPosition.X = textEditor.Lines.Count > textEditor.CursorPosition.Y ? textEditor.Lines[textEditor.CursorPosition.Y].TrimEnd().Length : 0;
|
||||
return true;
|
||||
|
||||
case ConsoleKey.R:
|
||||
ExecuteWithDebugScreen("run", false, false);
|
||||
return true;
|
||||
|
||||
case ConsoleKey.D:
|
||||
ExecuteWithDebugScreen("debug", true, false);
|
||||
return true;
|
||||
|
||||
case ConsoleKey.F:
|
||||
textEditor.FormatLines();
|
||||
textEditor.Display(true);
|
||||
@@ -352,6 +360,8 @@ internal class InputHandler(TextEditor textEditor)
|
||||
return;
|
||||
}
|
||||
|
||||
Mode previousMode = textEditor.EditMode;
|
||||
|
||||
textEditor.EditMode = Mode.Debug;
|
||||
textEditor.IsStepDebugMode = stepMode;
|
||||
Console.Clear();
|
||||
@@ -373,6 +383,6 @@ internal class InputHandler(TextEditor textEditor)
|
||||
_ = Console.ReadKey();
|
||||
WriteStatus(string.Empty);
|
||||
textEditor.IsStepDebugMode = false;
|
||||
textEditor.EditMode = Mode.Command;
|
||||
textEditor.EditMode = previousMode;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,7 +81,8 @@ internal static partial class Evaluator
|
||||
|
||||
/// <summary>
|
||||
/// Evaluates a numeric arithmetic expression string and returns the result as a string.
|
||||
/// Supports <c>+</c>, <c>-</c>, <c>*</c>, and <c>/</c> operators.
|
||||
/// Supports <c>+</c>, <c>-</c>, <c>*</c>, <c>/</c>, <c>%</c> (modulo), and <c>^</c> (power) operators
|
||||
/// with standard precedence (<c>^</c> highest, <c>+</c>/<c>-</c> lowest) and parentheses.
|
||||
/// Adjacent sign characters (<c>++</c>, <c>--</c>, <c>-+</c>, <c>+-</c>) are normalised before evaluation.
|
||||
/// </summary>
|
||||
/// <param name="input">The arithmetic expression to evaluate.</param>
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
# YesNt Documentation
|
||||
|
||||
YesNt is a line-based, interpreted scripting language inspired by assembly.
|
||||
Each line is one statement. There are no multi-line expressions.
|
||||
|
||||
## Guides
|
||||
|
||||
| Document | Description |
|
||||
| ------------------------------------------- | ---------------------------------------------------- |
|
||||
| [Language Reference](language-reference.md) | Every statement, token, and operator in the language |
|
||||
| [Library API](library-api.md) | How to embed the interpreter in a C# project |
|
||||
| [Editor](editor.md) | How to use the terminal code editor |
|
||||
|
||||
## Quick start
|
||||
|
||||
### Running a script from the command line
|
||||
|
||||
```bash
|
||||
dotnet run --project YesNt.Interpreter.App -- path/to/script.ynt
|
||||
```
|
||||
|
||||
### Hello world
|
||||
|
||||
```ynt
|
||||
print_line Hello, world!
|
||||
```
|
||||
|
||||
### Variables and output
|
||||
|
||||
```ynt
|
||||
var name = Alice
|
||||
print_line Hello, ${name}!
|
||||
```
|
||||
|
||||
### Functions
|
||||
|
||||
```ynt
|
||||
func greet:
|
||||
var msg = Hello, ${name}!
|
||||
print_line ${msg}
|
||||
return
|
||||
|
||||
var name = Bob
|
||||
call greet
|
||||
```
|
||||
|
||||
Script files use the `.ynt` extension by convention.
|
||||
@@ -0,0 +1,52 @@
|
||||
# YesNt Code Editor
|
||||
|
||||
`YesNt.CodeEditor` is a terminal editor for writing, formatting, running, and debugging YesNt scripts.
|
||||
|
||||
## Start the editor
|
||||
|
||||
```bash
|
||||
dotnet run --project YesNt.CodeEditor -- [optional-path-to-file.ynt]
|
||||
```
|
||||
|
||||
If you pass a file path, it is loaded on startup.
|
||||
|
||||
## Modes
|
||||
|
||||
- **Command mode:** enter editor commands in the `>>>` prompt.
|
||||
- **Edit mode:** direct text editing with keyboard navigation.
|
||||
- **Debug mode:** script output/debug information while running.
|
||||
|
||||
## Command mode commands
|
||||
|
||||
| Command | Description |
|
||||
| --------------------- | --------------------------------------------------------- |
|
||||
| `edit` | Switch to edit mode |
|
||||
| `line <n>` | Jump to line `n` and switch to edit mode |
|
||||
| `save [path]` | Save to current path or a new path |
|
||||
| `load <path>` | Load a file |
|
||||
| `new` | Create new file |
|
||||
| `format` | Auto-format indentation |
|
||||
| `run [path]` | Run script |
|
||||
| `debug [path] [step]` | Run in debug mode (`step` enables step-by-step execution) |
|
||||
| `exit` | Close the editor |
|
||||
|
||||
## Edit mode controls
|
||||
|
||||
- Arrow keys: move cursor
|
||||
- Enter: split line
|
||||
- Backspace/Delete: remove characters/merge lines
|
||||
- **Alt+C:** return to command mode
|
||||
- **Alt+T:** jump to top
|
||||
- **Alt+B:** jump to bottom
|
||||
- **Alt+S:** jump to start of line
|
||||
- **Alt+E:** jump to end of line
|
||||
- **Alt+R:** run script
|
||||
- **Alt+D:** run debug mode
|
||||
- **Alt+F:** format current file
|
||||
|
||||
## Formatter behavior (quick summary)
|
||||
|
||||
- Indents `func`, `if`, `else`, and `while` blocks.
|
||||
- Dedents on `return`, `end_if`, and `end_while`.
|
||||
- `exit` / `throw` / `error` close active non-function blocks for following lines.
|
||||
- Comment lines (`# ...`) are kept unindented.
|
||||
@@ -0,0 +1,811 @@
|
||||
# YesNt Language Reference
|
||||
|
||||
YesNt is a line-based scripting language. Every non-empty, non-comment line is one statement.
|
||||
Execution proceeds top-to-bottom unless a control-flow statement changes the line counter.
|
||||
|
||||
---
|
||||
|
||||
## Table of contents
|
||||
|
||||
1. [Basic rules](#basic-rules)
|
||||
2. [Comments](#comments)
|
||||
3. [String literals](#string-literals)
|
||||
4. [Variables](#variables)
|
||||
5. [Console I/O](#console-io)
|
||||
6. [Arithmetic](#arithmetic)
|
||||
7. [Conditions](#conditions)
|
||||
8. [Control flow](#control-flow)
|
||||
9. [Functions](#functions)
|
||||
10. [Lists](#lists)
|
||||
11. [Processing](#processing)
|
||||
12. [System](#system)
|
||||
13. [Predefined tokens](#predefined-tokens)
|
||||
14. [Termination](#termination)
|
||||
|
||||
---
|
||||
|
||||
## Basic rules
|
||||
|
||||
- Lines are trimmed of leading and trailing whitespace before execution.
|
||||
- Blank lines are silently skipped.
|
||||
- Lines starting with `#` are comments and are silently skipped.
|
||||
- Variable interpolation uses `${name}` and is evaluated before the statement runs.
|
||||
- Special characters inside string literals are encoded internally and decoded on output — this is transparent to scripts.
|
||||
|
||||
---
|
||||
|
||||
## Comments
|
||||
|
||||
```ynt
|
||||
# This is a comment.
|
||||
print_line Hello # inline comments are NOT supported — everything after print_line is the argument
|
||||
```
|
||||
|
||||
Only whole-line comments (lines whose first non-whitespace character is `#`) are supported.
|
||||
|
||||
---
|
||||
|
||||
## String literals
|
||||
|
||||
Double-quoted strings protect their content from keyword matching and allow escape sequences.
|
||||
|
||||
```ynt
|
||||
print_line "Hello, world!"
|
||||
print_line "Line one\nLine two"
|
||||
print_line "She said \"hi\""
|
||||
```
|
||||
|
||||
| Escape | Meaning |
|
||||
| ------ | -------------------- |
|
||||
| `\n` | Newline |
|
||||
| `\r` | Carriage return |
|
||||
| `\t` | Horizontal tab |
|
||||
| `\"` | Literal double-quote |
|
||||
| `\\` | Literal backslash |
|
||||
|
||||
Variable interpolation (`${name}`) is **not** evaluated inside string literals — the braces
|
||||
and content are passed through verbatim.
|
||||
|
||||
```ynt
|
||||
var x = world
|
||||
print_line "${x}" # prints the literal text: ${x}
|
||||
print_line "hello " ${x} # prints: hello world (interpolation outside the literal)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Variables
|
||||
|
||||
### Local variables — `var`
|
||||
|
||||
```
|
||||
var <name> = <value>
|
||||
```
|
||||
|
||||
Defines or updates a variable scoped to the current function (or the top level if called outside a function).
|
||||
The value is everything after `=`, trimmed.
|
||||
|
||||
```ynt
|
||||
var count = 0
|
||||
var greeting = Hello, world!
|
||||
```
|
||||
|
||||
Variable names may only contain letters and digits (`[a-zA-Z0-9]`).
|
||||
|
||||
### Global variables — `global`
|
||||
|
||||
```
|
||||
global <name> = <value>
|
||||
```
|
||||
|
||||
Defines or updates a variable that is visible across all function scopes and background tasks.
|
||||
|
||||
```ynt
|
||||
global total = 100
|
||||
```
|
||||
|
||||
### Reading a variable — `${name}`
|
||||
|
||||
`${name}` is an inline token that is replaced with the variable's value before the statement executes.
|
||||
It can appear anywhere in a line and multiple occurrences are replaced left to right.
|
||||
Local variables are checked first; if not found, the global table is checked.
|
||||
|
||||
```ynt
|
||||
var a = 5
|
||||
var b = 10
|
||||
print_line ${a} plus ${b}
|
||||
```
|
||||
|
||||
### Deleting a variable — `delete`
|
||||
|
||||
```
|
||||
delete <name>
|
||||
```
|
||||
|
||||
Removes the variable. Local scope is checked first; if not found, the global table is used.
|
||||
Raises an error if the variable does not exist in either scope.
|
||||
|
||||
```ynt
|
||||
var temp = scratch
|
||||
delete temp
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Console I/O
|
||||
|
||||
### Print with newline — `print_line`
|
||||
|
||||
```
|
||||
print_line <text>
|
||||
print_line
|
||||
```
|
||||
|
||||
Writes `<text>` followed by a newline. With no argument, writes a blank line.
|
||||
|
||||
```ynt
|
||||
print_line Hello!
|
||||
print_line
|
||||
print_line Done.
|
||||
```
|
||||
|
||||
### Print without newline — `print`
|
||||
|
||||
```
|
||||
print <text>
|
||||
```
|
||||
|
||||
Writes `<text>` without a trailing newline.
|
||||
|
||||
```ynt
|
||||
print Enter your name:
|
||||
var name = %read_line
|
||||
print_line Hello, ${name}!
|
||||
```
|
||||
|
||||
### Read a line of input — `%read_line`
|
||||
|
||||
`%read_line` is an inline token that is replaced with one line of text read from standard input.
|
||||
|
||||
```ynt
|
||||
var answer = %read_line
|
||||
print_line You typed: ${answer}
|
||||
```
|
||||
|
||||
### Read a single key — `%read_key`
|
||||
|
||||
`%read_key` is an inline token that is replaced with the single character pressed by the user (no Enter required).
|
||||
|
||||
```ynt
|
||||
print Press any key...
|
||||
var key = %read_key
|
||||
print_line You pressed: ${key}
|
||||
```
|
||||
|
||||
### Clear the console — `clear`
|
||||
|
||||
```
|
||||
clear
|
||||
```
|
||||
|
||||
Clears the console window.
|
||||
|
||||
---
|
||||
|
||||
## Arithmetic
|
||||
|
||||
Arithmetic is a **postfix** modifier applied at the end of a line with the `calc` keyword.
|
||||
|
||||
```
|
||||
<expression> calc
|
||||
```
|
||||
|
||||
Any numeric sub-expression matching the pattern `number op number [op number …]` is evaluated
|
||||
and replaced with the result. Supported operators (highest to lowest precedence):
|
||||
|
||||
| Operator | Operation |
|
||||
| -------- | ----------------------------- |
|
||||
| `(…)` | Parentheses (evaluated first) |
|
||||
| `^` | Exponentiation |
|
||||
| `%` | Modulo |
|
||||
| `/` | Division |
|
||||
| `*` | Multiplication |
|
||||
| `-` | Subtraction |
|
||||
| `+` | Addition (lowest precedence) |
|
||||
|
||||
Adjacent sign characters (`++`, `--`, `-+`, `+-`) are normalised before evaluation.
|
||||
|
||||
```ynt
|
||||
var x = 3
|
||||
var y = 4
|
||||
var sum = ${x} + ${y} calc # 7
|
||||
var expr = 2 + 3 * 4 calc # 14 (* before +)
|
||||
var parens = (2 + 3) * 4 calc # 20
|
||||
var power = 2 ^ 10 calc # 1024
|
||||
var remainder = 17 % 5 calc # 2
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Conditions
|
||||
|
||||
Conditions are used in `if` and `while` statements. A condition is a string of the form:
|
||||
|
||||
```
|
||||
<left> <operator> <right>
|
||||
```
|
||||
|
||||
| Operator | Meaning |
|
||||
| -------- | --------------------------------------------- |
|
||||
| `==` | Equal (string comparison, case-sensitive) |
|
||||
| `!=` | Not equal (string comparison, case-sensitive) |
|
||||
| `<` | Less than (numeric) |
|
||||
| `>` | Greater than (numeric) |
|
||||
| `<=` | Less than or equal (numeric) |
|
||||
| `>=` | Greater than or equal (numeric) |
|
||||
|
||||
Numeric comparisons (`<`, `>`, `<=`, `>=`) parse both sides with
|
||||
culture-invariant decimal rules (`.` or `,` as decimal separator).
|
||||
|
||||
A bare value of `True` or `False` (case-insensitive) is also a valid condition.
|
||||
|
||||
```ynt
|
||||
var x = 10
|
||||
if ${x} > 5:
|
||||
print_line x is greater than 5
|
||||
end_if
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Control flow
|
||||
|
||||
### If / else / end_if
|
||||
|
||||
```
|
||||
if <condition>:
|
||||
<body>
|
||||
else:
|
||||
<alternative>
|
||||
end_if
|
||||
```
|
||||
|
||||
`else:` is optional. `if` / `else:` / `end_if` blocks can be nested.
|
||||
|
||||
```ynt
|
||||
var score = 75
|
||||
if ${score} >= 60:
|
||||
print_line Pass
|
||||
else:
|
||||
print_line Fail
|
||||
end_if
|
||||
```
|
||||
|
||||
### While loop
|
||||
|
||||
```
|
||||
while <condition>:
|
||||
<body>
|
||||
end_while
|
||||
```
|
||||
|
||||
The condition is checked before each iteration. `while` / `end_while` blocks can be nested.
|
||||
|
||||
```ynt
|
||||
var i = 1
|
||||
while ${i} <= 5:
|
||||
print_line ${i}
|
||||
var i = ${i} + 1 calc
|
||||
end_while
|
||||
```
|
||||
|
||||
### Labels and goto
|
||||
|
||||
```
|
||||
label <name>:
|
||||
goto <name>
|
||||
```
|
||||
|
||||
`label` marks a target. `goto` performs an unconditional jump to that label.
|
||||
Labels are scoped to the current function; you cannot jump to a label outside the calling function.
|
||||
|
||||
```ynt
|
||||
label loop:
|
||||
print_line tick
|
||||
goto loop
|
||||
```
|
||||
|
||||
### Conditional goto
|
||||
|
||||
```
|
||||
if <condition> goto <label>
|
||||
```
|
||||
|
||||
Jumps to `<label>` only when the condition is true.
|
||||
|
||||
```ynt
|
||||
var n = 0
|
||||
label start:
|
||||
var n = ${n} + 1 calc
|
||||
if ${n} < 10 goto start
|
||||
print_line done
|
||||
```
|
||||
|
||||
### Conditional function call
|
||||
|
||||
```
|
||||
if <condition> call <function>
|
||||
```
|
||||
|
||||
Calls `<function>` only when the condition is true.
|
||||
|
||||
```ynt
|
||||
var debug = True
|
||||
if ${debug} == True call dump_state
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Functions
|
||||
|
||||
### Declaring a function — `func`
|
||||
|
||||
```
|
||||
func <name>:
|
||||
<body>
|
||||
return
|
||||
```
|
||||
|
||||
A function declaration registers the function name and the line it starts on.
|
||||
The body runs until `return` is reached.
|
||||
**Nested function declarations are not allowed.**
|
||||
|
||||
```ynt
|
||||
func add:
|
||||
var result = %in + %in calc
|
||||
push_out ${result}
|
||||
return
|
||||
```
|
||||
|
||||
### Calling a function — `call`
|
||||
|
||||
```
|
||||
call <name>
|
||||
call <name> with <arg1>, <arg2>, …
|
||||
```
|
||||
|
||||
`call` without `with` uses any values previously pushed with `push_in`.
|
||||
`call … with …` pushes the comma-separated arguments and then calls the function.
|
||||
|
||||
```ynt
|
||||
call greet
|
||||
call add with 3, 7
|
||||
```
|
||||
|
||||
### Input arguments
|
||||
|
||||
#### Push an input argument — `push_in`
|
||||
|
||||
```
|
||||
push_in <value>
|
||||
```
|
||||
|
||||
Pushes a value onto the input argument stack. Values are consumed in the order they were pushed —
|
||||
the first `push_in` call is the first value consumed by `%in` inside the function.
|
||||
|
||||
```ynt
|
||||
push_in Alice
|
||||
call greet
|
||||
```
|
||||
|
||||
#### Pop the next input argument — `%in`
|
||||
|
||||
`%in` is an inline token (only valid inside a function) that is replaced with the next value
|
||||
popped from the argument stack.
|
||||
|
||||
```ynt
|
||||
func greet:
|
||||
var name = %in
|
||||
print_line Hello, ${name}!
|
||||
return
|
||||
```
|
||||
|
||||
#### Check if input argument exists — `%has_in`
|
||||
|
||||
`%has_in` is replaced with `True` or `False` depending on whether the input stack is non-empty.
|
||||
Only valid inside a function.
|
||||
|
||||
```ynt
|
||||
func greet:
|
||||
if %has_in == True call do_greet
|
||||
return
|
||||
```
|
||||
|
||||
### Output values
|
||||
|
||||
#### Push an output value — `push_out`
|
||||
|
||||
```
|
||||
push_out <value>
|
||||
```
|
||||
|
||||
Only valid inside a function. Pushes a return value onto the output stack.
|
||||
|
||||
#### Consume an output value — `%out`
|
||||
|
||||
`%out` is an inline token that pops and inserts the top value from the output stack.
|
||||
Valid anywhere after a function call or list/processing statement that pushes to the output stack.
|
||||
|
||||
```ynt
|
||||
call add with 3, 7
|
||||
var total = %out
|
||||
print_line ${total}
|
||||
```
|
||||
|
||||
#### Check if output value exists — `%has_out`
|
||||
|
||||
`%has_out` is replaced with `True` or `False` depending on whether the output stack is non-empty.
|
||||
|
||||
```ynt
|
||||
call maybe_produce
|
||||
if %has_out == True call consume_result
|
||||
```
|
||||
|
||||
### Clear the call stack — `clear_call_stack`
|
||||
|
||||
```
|
||||
clear_call_stack
|
||||
```
|
||||
|
||||
Discards all frames on the function call stack. Useful for error recovery.
|
||||
|
||||
---
|
||||
|
||||
## Lists
|
||||
|
||||
Lists are ordered, mutable sequences of strings. All list operations start with the keyword `list`.
|
||||
|
||||
### Create or reset — `list … new`
|
||||
|
||||
```
|
||||
list <name> new
|
||||
```
|
||||
|
||||
Creates an empty list. If the list already exists it is cleared.
|
||||
|
||||
### Add an item — `list … add`
|
||||
|
||||
```
|
||||
list <name> add <value>
|
||||
```
|
||||
|
||||
Appends `<value>` to the end of the list.
|
||||
|
||||
### Get an item — `list … get`
|
||||
|
||||
```
|
||||
list <name> get <index>
|
||||
```
|
||||
|
||||
Pushes the item at zero-based `<index>` onto the output stack. Access it with `%out`.
|
||||
|
||||
```ynt
|
||||
list fruits new
|
||||
list fruits add apple
|
||||
list fruits add banana
|
||||
list fruits get 0
|
||||
var first = %out
|
||||
print_line ${first}
|
||||
```
|
||||
|
||||
### Set an item — `list … set`
|
||||
|
||||
```
|
||||
list <name> set <index> <value>
|
||||
```
|
||||
|
||||
Replaces the item at `<index>` with `<value>`.
|
||||
|
||||
### Remove an item — `list … remove`
|
||||
|
||||
```
|
||||
list <name> remove <index>
|
||||
```
|
||||
|
||||
Removes the item at `<index>`. Subsequent items shift down.
|
||||
|
||||
### Insert an item — `list … insert`
|
||||
|
||||
```
|
||||
list <name> insert <index> <value>
|
||||
```
|
||||
|
||||
Inserts `<value>` before position `<index>`.
|
||||
|
||||
### Get the length — `list … length`
|
||||
|
||||
```
|
||||
list <name> length
|
||||
```
|
||||
|
||||
Pushes the number of items onto the output stack.
|
||||
|
||||
```ynt
|
||||
list fruits length
|
||||
var n = %out
|
||||
print_line ${n} items
|
||||
```
|
||||
|
||||
### Clear all items — `list … clear`
|
||||
|
||||
```
|
||||
list <name> clear
|
||||
```
|
||||
|
||||
Removes all items but keeps the list alive.
|
||||
|
||||
### Delete a list — `list … delete`
|
||||
|
||||
```
|
||||
list <name> delete
|
||||
```
|
||||
|
||||
Removes the list entirely.
|
||||
|
||||
---
|
||||
|
||||
## Processing
|
||||
|
||||
### Arithmetic — `calc`
|
||||
|
||||
See [Arithmetic](#arithmetic).
|
||||
|
||||
### Decode a safe string — `eval`
|
||||
|
||||
```
|
||||
<expression> eval
|
||||
```
|
||||
|
||||
Decodes any internally-encoded characters in the current line back to their plain-text form.
|
||||
Useful after producing text from string literal operations that you want to re-use as plain text.
|
||||
|
||||
### Run from the current line in a background task — `task`
|
||||
|
||||
```
|
||||
<line> task
|
||||
```
|
||||
|
||||
Starts a background interpreter from the current line. In that background run, the current line is
|
||||
executed without the trailing `task`, and execution then continues through the remaining lines.
|
||||
The main script continues immediately. The task shares the global variable table with the main script.
|
||||
|
||||
```ynt
|
||||
print_line Starting background work... task
|
||||
print_line Main thread continues.
|
||||
```
|
||||
|
||||
#### Important behavior
|
||||
|
||||
- `task` does **not** run just one statement; it starts a second execution flow from that point onward.
|
||||
- Without careful control flow, lines after the `task` statement may run twice:
|
||||
once on the main thread and once in the background task.
|
||||
- Global variables are shared between both flows.
|
||||
|
||||
#### Recommended pattern
|
||||
|
||||
Use a direct function call with `task`, and terminate inside that function with `exit`.
|
||||
This keeps the worker logic isolated and avoids `goto` scaffolding.
|
||||
|
||||
```ynt
|
||||
call background_job task
|
||||
print_line Main thread keeps going
|
||||
|
||||
func background_job:
|
||||
print_line Work in background
|
||||
exit
|
||||
```
|
||||
|
||||
This works well for task-only worker flows. In non-task/shared flows, prefer `return` if you want
|
||||
to return to the caller instead of terminating that execution flow with `exit`.
|
||||
|
||||
### Sleep — `sleep`
|
||||
|
||||
```
|
||||
sleep <milliseconds>
|
||||
```
|
||||
|
||||
Pauses execution for the given number of milliseconds. Respects cancellation: if the script is
|
||||
stopped (e.g. via `abort_all` from another task), `sleep` returns early.
|
||||
|
||||
```ynt
|
||||
sleep 1000
|
||||
print_line One second later.
|
||||
```
|
||||
|
||||
### Get string length — `length`
|
||||
|
||||
```
|
||||
length <text>
|
||||
```
|
||||
|
||||
Pushes the character count of `<text>` onto the output stack.
|
||||
|
||||
```ynt
|
||||
length Hello, world!
|
||||
var len = %out
|
||||
print_line ${len}
|
||||
```
|
||||
|
||||
### Import another script — `import`
|
||||
|
||||
```
|
||||
import <path>
|
||||
```
|
||||
|
||||
Inlines the contents of another `.ynt` file at the current position.
|
||||
The extension `.ynt` is appended automatically if omitted.
|
||||
The path is resolved relative to the directory of the importing script.
|
||||
|
||||
```ynt
|
||||
import utils
|
||||
import lib/math.ynt
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## System
|
||||
|
||||
### Execute a program — `exec`
|
||||
|
||||
```
|
||||
exec <program>
|
||||
exec <program> with <arg1>, <arg2>, …
|
||||
```
|
||||
|
||||
Runs an external program and waits for it to finish.
|
||||
Standard output and standard error are forwarded to the console in real time.
|
||||
The exit code and each line of output are pushed onto the output stack (exit code on top).
|
||||
|
||||
```ynt
|
||||
exec notepad
|
||||
exec git with status, --short
|
||||
var exit_code = %out
|
||||
print_line Exited with ${exit_code}
|
||||
```
|
||||
|
||||
You can also stage arguments with `push_in` before a bare `exec`:
|
||||
|
||||
```ynt
|
||||
push_in --version
|
||||
exec python
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Predefined tokens
|
||||
|
||||
These inline tokens are replaced with their value before the statement executes.
|
||||
|
||||
| Token | Replaced with |
|
||||
| ------- | --------------------------------------------------- |
|
||||
| `%time` | Current Unix timestamp (seconds) |
|
||||
| `%os` | Operating system platform name (e.g. `Win32NT`) |
|
||||
| `%cpu` | Processor architecture (e.g. `X64`) |
|
||||
| `%is64` | `True` if the OS is 64-bit, otherwise `False` |
|
||||
| `%pi` | The value of π |
|
||||
| `%rand` | A random integer in the range `[32767, 2147483647)` |
|
||||
|
||||
```ynt
|
||||
print_line Time: %time
|
||||
print_line OS: %os
|
||||
print_line PI: %pi
|
||||
var roll = %rand
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Termination
|
||||
|
||||
### Normal exit — `exit`
|
||||
|
||||
```
|
||||
exit
|
||||
```
|
||||
|
||||
Terminates the script gracefully. Background tasks that are still running are not cancelled.
|
||||
|
||||
### Exit and cancel all tasks — `abort_all`
|
||||
|
||||
```
|
||||
abort_all
|
||||
```
|
||||
|
||||
Terminates the script and signals all background tasks to stop.
|
||||
|
||||
### Throw an error — `throw`
|
||||
|
||||
```
|
||||
throw <message>
|
||||
```
|
||||
|
||||
Terminates the script and all tasks with `<message>` as the error description.
|
||||
A stack trace is printed showing the line and file where the error occurred.
|
||||
|
||||
```ynt
|
||||
var x = -1
|
||||
if ${x} < 0 call validate_fail
|
||||
|
||||
func validate_fail:
|
||||
throw x must not be negative
|
||||
return
|
||||
```
|
||||
|
||||
### Non-fatal error — `error`
|
||||
|
||||
```
|
||||
error <message>
|
||||
```
|
||||
|
||||
Like `throw` but does **not** cancel background tasks.
|
||||
|
||||
---
|
||||
|
||||
## Full statement reference
|
||||
|
||||
| Statement | Form | Description |
|
||||
| ------------------ | ------------------------------ | ------------------------------------------------------------ |
|
||||
| `var` | `var name = value` | Define/update local variable |
|
||||
| `global` | `global name = value` | Define/update global variable |
|
||||
| `delete` | `delete name` | Delete variable |
|
||||
| `print_line` | `print_line [text]` | Print line (optional text) |
|
||||
| `print` | `print text` | Print without newline |
|
||||
| `clear` | `clear` | Clear console |
|
||||
| `if … :` | `if cond:` | Start conditional block |
|
||||
| `else:` | `else:` | Else branch |
|
||||
| `end_if` | `end_if` | End conditional block |
|
||||
| `while … :` | `while cond:` | Start while loop |
|
||||
| `end_while` | `end_while` | End while loop |
|
||||
| `label` | `label name:` | Declare a jump target |
|
||||
| `goto` | `goto name` | Unconditional jump |
|
||||
| `if … goto` | `if cond goto name` | Conditional jump |
|
||||
| `func` | `func name:` | Declare a function |
|
||||
| `call` | `call name` | Call a function |
|
||||
| `call … with` | `call name with a, b` | Call a function with arguments |
|
||||
| `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 |
|
||||
| `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 |
|
||||
| `list … get` | `list name get index` | Get item → `%out` |
|
||||
| `list … set` | `list name set index value` | Replace item |
|
||||
| `list … remove` | `list name remove index` | Remove item |
|
||||
| `list … insert` | `list name insert index value` | Insert item |
|
||||
| `list … length` | `list name length` | Get count → `%out` |
|
||||
| `list … clear` | `list name clear` | Clear all items |
|
||||
| `list … delete` | `list name delete` | Delete list |
|
||||
| `calc` | `expr calc` | Evaluate arithmetic |
|
||||
| `eval` | `expr eval` | Decode string encoding |
|
||||
| `task` | `line task` | Run current line (without `task`) and continue in background |
|
||||
| `sleep` | `sleep ms` | Sleep N milliseconds |
|
||||
| `length` | `length text` | Get char count → `%out` |
|
||||
| `import` | `import path` | Inline-include a `.ynt` file |
|
||||
| `exec` | `exec prog` | Run external program |
|
||||
| `exec … with` | `exec prog with a, b` | Run external program with args |
|
||||
| `exit` | `exit` | Graceful exit |
|
||||
| `abort_all` | `abort_all` | Exit and cancel all tasks |
|
||||
| `throw` | `throw message` | Fatal error (cancels all tasks) |
|
||||
| `error` | `error message` | Non-fatal error |
|
||||
| `%read_line` | inline | Insert one line of user input |
|
||||
| `%read_key` | inline | Insert one keypress |
|
||||
| `%in` | inline | Pop next function input argument |
|
||||
| `%has_in` | inline | `True`/`False` if input stack non-empty |
|
||||
| `%out` | inline | Pop top output value |
|
||||
| `%has_out` | inline | `True`/`False` if output stack non-empty |
|
||||
| `%time` | inline | Unix timestamp |
|
||||
| `%os` | inline | OS platform |
|
||||
| `%cpu` | inline | Processor architecture |
|
||||
| `%is64` | inline | `True` if 64-bit OS |
|
||||
| `%pi` | inline | Value of π |
|
||||
| `%rand` | inline | Random integer |
|
||||
@@ -0,0 +1,265 @@
|
||||
# YesNt Library API
|
||||
|
||||
The `YesNt.Interpreter` project is a .NET 8 class library. You can reference it from any C# project
|
||||
to embed the YesNt interpreter and run scripts programmatically.
|
||||
|
||||
---
|
||||
|
||||
## Table of contents
|
||||
|
||||
1. [Adding the reference](#adding-the-reference)
|
||||
2. [Running a script file](#running-a-script-file)
|
||||
3. [Running an in-memory script](#running-an-in-memory-script)
|
||||
4. [Capturing output (debug mode)](#capturing-output-debug-mode)
|
||||
5. [Adding custom statements](#adding-custom-statements)
|
||||
6. [Stopping a script](#stopping-a-script)
|
||||
7. [Reading registered statements](#reading-registered-statements)
|
||||
8. [API reference](#api-reference)
|
||||
|
||||
---
|
||||
|
||||
## Adding the reference
|
||||
|
||||
Add a project reference to `YesNt.Interpreter` in your `.csproj`:
|
||||
|
||||
```xml
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\YesNt.Interpreter\YesNt.Interpreter.csproj" />
|
||||
</ItemGroup>
|
||||
```
|
||||
|
||||
Then add the using directive:
|
||||
|
||||
```csharp
|
||||
using YesNt.Interpreter.Runtime;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Running a script file
|
||||
|
||||
```csharp
|
||||
var interpreter = new YesNtInterpreter();
|
||||
interpreter.Execute("path/to/script.ynt");
|
||||
```
|
||||
|
||||
`Execute` is synchronous - it returns when the script finishes (or terminates with an error).
|
||||
|
||||
---
|
||||
|
||||
## Running an in-memory script
|
||||
|
||||
Supply a `List<string>` instead of a file path:
|
||||
|
||||
```csharp
|
||||
var lines = new List<string>
|
||||
{
|
||||
"var x = 42",
|
||||
"print_line The answer is ${x}",
|
||||
};
|
||||
|
||||
var interpreter = new YesNtInterpreter();
|
||||
interpreter.Execute(lines);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Capturing output (debug mode)
|
||||
|
||||
Pass `isDebugMode: true` to suppress direct console writes. Output is delivered through the
|
||||
`OnDebugOutput` event instead, and `OnLineExecuted` fires after executed lines.
|
||||
|
||||
```csharp
|
||||
var interpreter = new YesNtInterpreter();
|
||||
var output = new System.Text.StringBuilder();
|
||||
|
||||
interpreter.OnDebugOutput += text => output.Append(text);
|
||||
interpreter.OnLineExecuted += args =>
|
||||
{
|
||||
if (args is null)
|
||||
{
|
||||
// null means execution reached end-of-file (EOF)
|
||||
Console.WriteLine("Script reached EOF.");
|
||||
return;
|
||||
}
|
||||
Console.WriteLine($"Line {args.LineNumber}: {args.CurrentLine}");
|
||||
};
|
||||
|
||||
interpreter.Execute(new List<string> { "print_line hello" }, isDebugMode: true);
|
||||
Console.Write(output);
|
||||
```
|
||||
|
||||
`OnLineExecuted` receives a `DebugEventArgs` with:
|
||||
|
||||
| Property | Type | Description |
|
||||
| -------------- | -------- | ------------------------------------------- |
|
||||
| `LineNumber` | `int` | 1-based line number |
|
||||
| `OriginalLine` | `string` | Raw source text |
|
||||
| `CurrentLine` | `string` | Text after all substitutions |
|
||||
| `IsTask` | `bool` | `true` if executed inside a background task |
|
||||
| `TaskId` | `int` | Task identifier (0 for the main thread) |
|
||||
|
||||
`OnLineExecuted` is invoked with `null` only when execution reaches end-of-file (EOF).
|
||||
If execution stops via `exit`, `throw`, `error`, or `Stop()`, no terminal `null` event is emitted.
|
||||
|
||||
---
|
||||
|
||||
## Adding custom statements
|
||||
|
||||
Use `AddStatement` to register keywords before calling `Execute`.
|
||||
|
||||
### Simple keyword at the start of a line
|
||||
|
||||
```csharp
|
||||
using YesNt.Interpreter.Enums;
|
||||
|
||||
var interpreter = new YesNtInterpreter();
|
||||
|
||||
interpreter.AddStatement("log", SearchMode.StartOfLine, SpaceAround.End, args =>
|
||||
{
|
||||
Console.WriteLine($"[LOG] {args}");
|
||||
});
|
||||
|
||||
interpreter.Execute(new List<string> { "log Hello from custom statement" });
|
||||
```
|
||||
|
||||
### With a syntax-highlight colour
|
||||
|
||||
```csharp
|
||||
interpreter.AddStatement("log", SearchMode.StartOfLine, SpaceAround.End,
|
||||
ConsoleColor.Cyan,
|
||||
args => Console.WriteLine($"[LOG] {args}"));
|
||||
```
|
||||
|
||||
### Using a pre-built `StatementAttribute`
|
||||
|
||||
```csharp
|
||||
using YesNt.Interpreter.Attributes;
|
||||
|
||||
var attr = new StatementAttribute("log", SearchMode.StartOfLine, SpaceAround.End)
|
||||
{
|
||||
Priority = Priority.VeryLow,
|
||||
};
|
||||
|
||||
interpreter.AddStatement(attr, args => Console.WriteLine($"[LOG] {args}"));
|
||||
```
|
||||
|
||||
### `SearchMode` values
|
||||
|
||||
| Value | The keyword matches when… |
|
||||
| ------------- | -------------------------------------------- |
|
||||
| `StartOfLine` | the line **starts with** the keyword |
|
||||
| `EndOfLine` | the line **ends with** the keyword |
|
||||
| `Contains` | the keyword appears **anywhere** in the line |
|
||||
| `Exact` | the line is **exactly** the keyword |
|
||||
|
||||
### `SpaceAround` values
|
||||
|
||||
| Value | Space requirement |
|
||||
| ---------- | -------------------------------- |
|
||||
| `None` | No surrounding spaces required |
|
||||
| `Start` | A space must precede the keyword |
|
||||
| `End` | A space must follow the keyword |
|
||||
| `StartEnd` | Spaces required on both sides |
|
||||
|
||||
Custom statements run at `Priority.Normal` by default. Lower priority values run first.
|
||||
Use `StatementAttribute.Priority` to control ordering relative to built-in statements.
|
||||
|
||||
---
|
||||
|
||||
## Stopping a script
|
||||
|
||||
```csharp
|
||||
var interpreter = new YesNtInterpreter();
|
||||
|
||||
// Start the script on a background thread so we can stop it from this thread.
|
||||
var thread = new System.Threading.Thread(() =>
|
||||
interpreter.Execute(new List<string> { "while True:", "sleep 100", "end_while" }));
|
||||
|
||||
thread.Start();
|
||||
System.Threading.Thread.Sleep(500);
|
||||
interpreter.Stop(); // signals the script to terminate at the next line boundary
|
||||
thread.Join();
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Reading registered statements
|
||||
|
||||
`StatementInformation` returns a read-only snapshot of every registered statement.
|
||||
This is useful for building syntax highlighters or tooling.
|
||||
|
||||
```csharp
|
||||
var interpreter = new YesNtInterpreter();
|
||||
|
||||
foreach (var info in interpreter.StatementInformation)
|
||||
{
|
||||
Console.WriteLine($"{info.Name,-20} {info.SearchMode,-12} color={info.Color}");
|
||||
}
|
||||
```
|
||||
|
||||
Each `StatementInformation` object exposes:
|
||||
|
||||
| Property | Type | Description |
|
||||
| -------------------------- | -------------- | ---------------------------- |
|
||||
| `Name` | `string` | The keyword |
|
||||
| `SearchMode` | `SearchMode` | Where the keyword is matched |
|
||||
| `SpaceAround` | `SpaceAround` | Required surrounding spaces |
|
||||
| `Color` | `ConsoleColor` | Syntax-highlight colour |
|
||||
| `IgnoreSyntaxHighlighting` | `bool` | Whether to skip highlighting |
|
||||
| `Separator` | `string?` | Optional required sub-string |
|
||||
|
||||
---
|
||||
|
||||
## API reference
|
||||
|
||||
### `YesNtInterpreter`
|
||||
|
||||
```csharp
|
||||
public class YesNtInterpreter
|
||||
```
|
||||
|
||||
#### Constructor
|
||||
|
||||
```csharp
|
||||
public YesNtInterpreter()
|
||||
```
|
||||
|
||||
Creates a new interpreter instance and registers all built-in statements.
|
||||
|
||||
#### Events
|
||||
|
||||
```csharp
|
||||
public event Action<string> OnDebugOutput;
|
||||
public event Action<DebugEventArgs> OnLineExecuted;
|
||||
```
|
||||
|
||||
Only raised in debug mode (`isDebugMode: true`).
|
||||
`OnLineExecuted` receives `null` only on EOF completion.
|
||||
|
||||
#### Methods
|
||||
|
||||
```csharp
|
||||
// Execute a .ynt file
|
||||
public void Execute(string path, bool isDebugMode = false);
|
||||
|
||||
// Execute in-memory lines
|
||||
public void Execute(List<string> lines, bool isDebugMode = false);
|
||||
|
||||
// Register a custom statement (full control)
|
||||
public void AddStatement(StatementAttribute attribute, Action<string> handler);
|
||||
|
||||
// Register a custom statement (convenience overloads)
|
||||
public void AddStatement(string name, SearchMode searchMode, SpaceAround spaceAround, Action<string> handler);
|
||||
public void AddStatement(string name, SearchMode searchMode, SpaceAround spaceAround, ConsoleColor color, Action<string> handler);
|
||||
|
||||
// Request graceful stop
|
||||
public void Stop();
|
||||
```
|
||||
|
||||
#### Properties
|
||||
|
||||
```csharp
|
||||
// Read-only snapshot of all registered statements
|
||||
public ReadOnlyCollection<StatementInformation> StatementInformation { get; }
|
||||
```
|
||||
Reference in New Issue
Block a user