vextoly/cryn
Delete TUTORIAL.md
Commit ba0bc70 · Vextoly · 2026-10-04T15:39:58+02:00
Comments
No comments yet.
Diff
diff --git a/TUTORIAL.md b/TUTORIAL.md
deleted file mode 100644
index 64fe07f..0000000
--- a/TUTORIAL.md
+++ /dev/null
@@ -1,769 +0,0 @@
-# Learning Cryn: A Tutorial
-
-This tutorial teaches Cryn from zero. It explains the machine, not just
-the commands. Every example compiles with the current `cryn` compiler.
-
----
-
-## 1. Hello, machine
-
-```text
-define main
- set 10
- push
-
- set 20
- add
-
- output
-
- return
-end
-```
-
-Run it:
-
-```sh
-cryn run hello.cryn
-```
-
-Output:
-
-```text
-30
-```
-
-What happened?
-
-* `define main ... end` defines a **transformation** — Cryn's unit of
- computation. Execution starts at `main`.
-* `set 10` puts 10 into the **working value**: the one value your
- context is currently holding.
-* `push` copies the working value onto the **value stack** so it
- survives while we use the working value for something else.
-* `set 20` replaces the working value with 20.
-* `add` pops the stack and adds it to the working value: 20 + 10 = 30.
-* `output` writes the working value to stdout (integers print in
- decimal).
-* `return` ends the transformation.
-
-Formatting never matters. This is the same program:
-
-```text
-define main set 10 push set 20 add output return end
-```
-
-So is this:
-
-```text
-define
-main
-set
-10
-push
-set
-20
-add
-output
-return
-end
-```
-
-Comments are `[# ... #]` and may span lines. They are the only comment
-syntax:
-
-```text
-set 10 [# working value is ten #]
-```
-
-## 2. The machine you are driving
-
-Every running transformation is an **execution context** containing:
-
-1. A **working value** — one typed value, the thing commands operate on.
-2. A **value stack** — for saving values temporarily.
-3. A **focus** — a stack of currently selected **cells**; the bottom of
- the stack is the **frame root** (the transformation's own namespace).
-4. A **comparison state** — set by `compare`, tested by conditional
- jumps.
-
-The **world** is the collection of cells. Some cells belong to your
-frame (locals and parameters). Some belong to everyone (world cells,
-made at the top level). Blocks of raw memory are cells too.
-
-Data flows through three registers of attention:
-
-```text
-world cells <--move/read/write--> focus
-working value <--set/read/push/pop/arith--> value stack / literals
-```
-
-## 3. Cells: make, move, read, write
-
-A cell is a named place that holds one value:
-
-```text
-define main
- make int64 x [# a cell named x, holding an int64, starting at 0 #]
-
- set 41
- move x [# focus the cell x #]
- write [# x := working value (41) #]
-
- move x
- read [# working value := x #]
- add 1
- move x
- write [# x := 42 #]
-
- move x
- read
- output
- return
-end
-```
-
-This prints `42`.
-
-* `make int64 x` creates cell `x` in the current frame. Executing the
- `make` again re-zeroes it.
-* `move x` follows the **named connection** `x` from the frame root and
- focuses the cell. `move` with a name always resolves from the frame
- root, and it **anchors** the focus: the previous focus is replaced.
-* `read` copies the focused cell into the working value.
-* `write` copies the working value into the focused cell.
-
-Cell types are checked at compile time. Try writing a string address
-into an `int64` cell and the compiler refuses.
-
-### All the integer types
-
-```text
-int8 int16 int32 int64 signed
-uint8 uint16 uint32 uint64 unsigned
-float32 float64 floats
-bool char nothing
-```
-
-`make uint8 c`, `make float32 f`, `make bool b` — all work the same.
-`set 'A'` is a character literal; `set true` a boolean.
-
-## 4. Arithmetic
-
-Arithmetic works on the working value, either with a literal operand or
-by popping the stack:
-
-```text
-set 2
-add 3 [# 5 ]
-multiply 4 [# 20 ]
-subtract 5 [# 15 ]
-
-set 100
-push
-set 7
-divide [# pops 100, working value 7 -> 0.07? No: integer 7/100 is 0 ]
-```
-
-Careful: `divide` combines *working value* with *popped value*: the
-popped value is the right-hand operand. `100 pushed, working value 7`
-computes `7 / 100`.
-
-The exact rules (LANGUAGE.md §5, §7):
-
-* Integer overflow **wraps** in both directions. `set 9223372036854775807
- add 1` gives `-9223372036854775808`.
-* Division by zero aborts the program with a diagnostic. `-7 / 2` is
- `-3` (truncates toward zero).
-* Mixing widths: the wider type wins; mixed signedness becomes signed.
- Different types otherwise require `convert`:
- `set 1 convert float32 divide 3`.
-* `negate` flips the sign.
-
-```text
-set 1.5
-add 2.25 [# 3.75 ]
-multiply 2 [# 7.5 ]
-output [# prints 7.5 ]
-```
-
-Floats print as the shortest decimal that reads back exactly.
-
-## 5. Comparison and branching
-
-There is no `if`. There is `compare` and conditional `jump`:
-
-```text
-set 10
-compare 20
-jump smaller when less
-set 'N'
-jump done
-
-mark smaller
-set 'Y'
-
-mark done
-output
-```
-
-`compare 20` compares the working value (10) with 20 and sets the
-comparison state. `jump smaller when less` jumps when the state is
-`less`. Conditions: `less equal greater different less-or-equal
-greater-or-equal`.
-
-`compare` without an operand pops the stack:
-
-```text
-move a
-read
-push
-move b
-read
-compare [# b (working) vs a (popped) #]
-```
-
-Labels (`mark`) are transformation-scoped names. Any jump may go forward
-or backward.
-
-### The pattern for if/else
-
-```text
-compare 0
-jump negative when less
-set 1 [# then-branch #]
-jump end
-mark negative
-set 0 [# else-branch #]
-mark end
-```
-
-## 6. Loops
-
-A loop is a backward jump. Both of these print the numbers 0 through 4:
-
-```text
-make int64 i
-make int64 n
-
-set 0
-move i
-write
-set 5
-move n
-write
-set 0
-
-mark loop
-move i
-read
-compare 5
-jump done when greater-or-equal
-move i
-read
-push
-call newline
-pop
-output
-
-move i
-read
-add 1
-move i
-write
-set 0
-
-jump loop
-mark done
-```
-
-### The one rule you must know about loops
-
-The checker tracks the working value type, the focus, and the value
-stack at every label. **Every path that reaches a label must agree.**
-The back edge of a loop and the loop's entry must carry:
-
-* the same working value **type** (integer literals widen to the type
- they fit),
-* the same focus,
-* the same value stack shape.
-
-The reliable idiom: before entering a loop and before jumping back,
-normalize with `set 0` and `home`:
-
-```text
-set 0
-home
-mark loop
- ...
- set 0
- home
- jump loop
-```
-
-If you forget, the compiler tells you exactly where the two paths
-disagree — for example *"working value type differs between paths (0 vs
-int64); normalize it with 'set'"*.
-
-(This strictness is deliberate: it keeps every program point typed and
-lets the compiler emit plain C locals.)
-
-## 7. The value stack: push, pop, swap
-
-The stack exists to preserve values while the working value does
-something else:
-
-```text
-set 1
-push [# stack: 1 ]
-set 2
-add [# pops 1: working value 3 ]
-```
-
-* `push` copies the working value to the stack (the working value is
- unchanged).
-* `pop` brings the top back into the working value.
-* `swap` exchanges working value and stack top.
-
-The stack must be empty at `return`. The compiler enforces this; there
-are no leaks.
-
-## 8. Transformations: parameters and results
-
-```text
-define gcd int64 a int64 b result int64
- mark loop
- move b
- read
- compare 0
- jump done when equal
-
- move b
- read
- push
- move b
- read
- push
- move a
- read
- remainder
- push
- move b
- write
- pop
- pop
- move a
- write
- set nothing
- home
- jump loop
-
- mark done
- move a
- read
- return
-end
-
-define main
- set 252
- push
- set 105
- push
- call gcd
- output
- return
-end
-```
-
-This prints `21`.
-
-* Parameters are `{ type name }` pairs after the transformation name.
- They are ordinary frame cells.
-* **Arguments are pushed in parameter order** (first parameter deepest);
- `call` pops them into the parameter cells.
-* The **result is the working value at return**. `result int64` declares
- it; without a declaration it is inferred from the first `return`.
- Recursive transformations must declare `result`.
-* After a call, the caller's working value is the callee's result —
- unless the result is `nothing`, in which case the caller's working
- value is preserved.
-* A helper that returns nothing should end with `set nothing` before
- `return` (a stray value would become its result type):
-
-```text
-make string "\n" nl
-
-define newline result nothing
- address nl
- output text
- set nothing
- return
-end
-```
-
-Calls may recurse (one real frame per call); mutual recursion just
-works.
-
-### Transform references and callbacks
-
-`address transformation-name` produces a `transform` reference value.
-`call` without a name calls it. References can be passed as arguments:
-
-```text
-define ping result nothing
- make string "ping
-" msg
- address msg
- output text
- set nothing
- return
-end
-
-define twice transform f result nothing
- move f
- read
- push
- call
- pop
- call
- set nothing
- return
-end
-
-define main
- address ping
- push
- call twice
- return
-end
-```
-
-(Indirect calls target zero-parameter transformations in this version.)
-
-## 9. Arrays: indexed connections
-
-An array is a cell with indexed connections. Create with
-`make array N of T name`:
-
-```text
-make array 5 of int64 a
-```
-
-Two ways to reach an element:
-
-```text
-[# static index #]
-set 7
-move a
-move 0 [# element 0 #]
-write
-
-[# dynamic index: put the index in the working value FIRST #]
-move i
-read [# working value = i #]
-move a [# focus array; working value survives named moves #]
-move index [# element i; uses the working value as index #]
-read
-```
-
-Out-of-bounds indexing aborts the program with a diagnostic (the checker
-catches constant indices at compile time).
-
-The full array idiom, summed up: **index into the working value, then
-focus, then `move index`**. If you need the index afterwards, push it
-first and pop after.
-
-## 10. Strings
-
-A string is a byte array with a terminating NUL — nothing more:
-
-```text
-make string "Hello, World!" msg
-address msg
-output text
-```
-
-* `make string "..." msg` creates a byte-array cell.
-* `make string "..."` (no name) points the working value at static
- NUL-terminated bytes.
-* `output text` writes bytes until the NUL.
-
-To process text, loop over bytes:
-
-```text
-make string "interrupt" word
-make int64 n
-set 0
-move n
-write
-set 0
-
-mark count
-move n
-read
-move word
-move index
-read
-compare 0
-jump counted when equal
-move n
-read
-add 1
-move n
-write
-set 0
-jump count
-mark counted
-```
-
-`input` reads one byte (returns -1 at end of input); `output` of a
-`uint8` or `char` writes one raw byte. That is the whole I/O vocabulary;
-word counters and parsers are built from it (see `examples/`).
-
-## 11. Memory: blocks and addresses
-
-Manual memory, no garbage collector:
-
-```text
-make 4 of int64 block [# heap block of 4 int64s, zeroed #]
-```
-
-After a dynamic `make`, the working value holds the block's address
-(type `address array of int64`). Two idioms:
-
-```text
-[# write element 0 immediately: the address is still in the working value #]
-move at [# focus the block #]
-set 40
-move 0
-write
-back [# back to the block #]
-
-[# write element i for a computed i #]
-move i
-read
-push [# save the index #]
-move block
-read [# working value := block address #]
-move at [# focus the block #]
-pop [# restore the index #]
-move index [# focus element i #]
-set 41
-write
-```
-
-`free` releases a heap block:
-
-```text
-move block
-read
-free
-```
-
-### Addresses are values
-
-* `address x` — working value := the address of cell `x` (or of a
- transformation: a `transform` reference).
-* `address` (no name) — the address of the focused cell.
-* `move at` — focus the cell an address points to.
-* `add 1` / `subtract 1` on an address moves by **one element**
- (scaled by the element size), like pointer arithmetic in C.
-* Converting between `int64`/`uint64` and addresses reinterprets bits —
- that is how you store links inside homogeneous blocks.
-
-Addresses compare (`compare`) as unsigned numbers; `compare 0` tests
-for the null address.
-
-## 12. Structures and linked lists
-
-There is no `struct` command. A structure is a block of memory; fields
-are elements; links are addresses stored as integers. A linked list node
-`[ value next ]` is a block of two `int64`s:
-
-```text
-make 2 of int64 n1 [# value=10, next -> n2 #]
-make 2 of int64 n2 [# value=20, next = 0 #]
-make 2 of int64 cur
-
-move n2
-read
-move at
-set 20
-move 0
-write
-back
-set 0
-move 1
-write
-back
-
-move n2
-read
-convert int64 [# the link, as a number #]
-push
-move n1
-read
-move at
-set 10
-move 0
-write
-back
-move 1
-pop
-write
-back
-```
-
-Walking means converting the stored link back to an address:
-
-```text
-move cur
-read
-move at
-move 1
-read [# the next link #]
-convert address array of int64
-move cur
-write
-```
-
-The complete working program is `examples/linkedlist.cryn`.
-
-## 13. Files and the outside world
-
-Each context has a current input and output stream (stdin/stdout by
-default). `open` reroutes them through a file:
-
-```text
-make string "out.txt" path
-address path
-open write [# create/truncate; negative result = failure #]
-compare 0
-jump failed when less
-
-set 'H'
-output [# goes to the file #]
-
-close
-stop
-
-mark failed
-stop
-```
-
-`open read` reroutes input; `input` then reads the file byte by byte
-until it returns `-1`. `open both` opens for reading and writing.
-`system` runs a shell command:
-
-```text
-make string "touch cryn.txt" cmd
-address cmd
-system
-```
-
-There are no per-file read/write commands and no sockets in v1 — one
-context tracks one stream pair at a time (documented limitation). Files,
-networks, and devices are all expected to grow from this small surface.
-
-## 14. Concurrency
-
-```text
-make int64 counter
-
-define worker
- make int64 k
- set 0
- move k
- write
- mark w
- move k
- read
- compare 100
- jump done when greater-or-equal
- move counter
- read
- add 1
- move counter
- write
- set 0
- move k
- read
- add 1
- move k
- write
- set 0
- jump w
- mark done
- return
-end
-
-define main
- spawn worker
- spawn worker
- wait
- move counter
- read
- output
- return
-end
-```
-
-`spawn name` starts a new context (a real thread) running a
-zero-parameter transformation. Contexts share world cells and heap
-blocks — that is how they communicate. `wait` joins everything this
-context spawned and makes all their writes visible. Without `wait` there
-are no ordering guarantees. This is a minimal, honest model: v1 has no
-locks or atomics.
-
-## 15. A real program
-
-`examples/wordcount.cryn` counts lines, words, and characters from
-stdin using: world cells, a bump helper that increments a cell through
-its address, byte classification with `compare`, and normalization at
-loop labels. Run it:
-
-```sh
-cryn run examples/wordcount.cryn < examples/wordcount.cryn
-```
-
-Other complete programs in `examples/`: `sorting.cryn` (bubble sort over
-a heap block with element helpers), `allocator.cryn` (a free-list
-allocator), `linkedlist.cryn`, `fib.cryn`, `fizzbuzz.cryn`.
-
-## 16. When the compiler argues with you
-
-The checker is strict so that the machine stays simple. The errors you
-will meet and what they mean:
-
-* *"working value type differs between paths"* — normalize with `set`
- at loop entries and back edges.
-* *"focus depth/type differs between paths"* — add `home` (or `back`)
- before jumps into shared labels.
-* *"the value stack must be empty at return"* — you pushed something
- and never popped it.
-* *"cannot write X into a cell of type Y"* — types match exactly or you
- `convert` first (literals adapt automatically when they fit).
-* *"unreachable command"* — code after an unconditional jump with no
- label bringing it back to life. Delete it or label it.
-* *"'move index' requires an integer working value"* — get the index
- into the working value *before* focusing the array (§9).
-
-## 17. The whole language
-
-You have now seen every mechanism. Thirty-four commands:
-
-```text
-move back home address make free read write
-set add subtract multiply divide remainder negate
-push pop swap compare convert
-jump call return stop
-input output open close system
-spawn wait define end mark
-```
-
-Everything else — control flow, arrays, structures, strings, pointers,
-callbacks — is patterns built from these. When you wonder "how do I do X
-in Cryn?", ask instead: *"what does the machine have to do to make X
-happen?"* — and write that.
-
-Welcome to the machine.