aboutsummaryrefslogtreecommitdiff
path: root/docs/history/52-closures/notes.md
blob: 335923ea06b1ef6f57087092e95c06914a4367e0 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 52 closures

closures compiled and built their value, but calling one halted the program silently with exit 0.

cause: the vm only runs code inside the code area (the interpreter loop runs while `pc < PW`). a closure's body was copied into a heap block, so a call into it left the loop without an error.

fix (`src/compiler.zc`):
- the closure block is a heap value whose word 0 is the body's entry. captured variables start at word 3, and the env the body receives is block + 3, so the body reads capture `i` at env + `i` as before.
- a call through a value compares the callee with `HEAP_LO`. below it, the call goes straight to the function as before. at or above it, the call pushes block + 3 as the env, loads the entry from word 0, and calls that. both paths meet at the same result handling.
- a capture of a variable from further out is chained through each closure in between (`clocap_at`). `clo_via` records the slot in the enclosing closure's environment that the new closure copies from.

checks: `tests/closure.zc` (interpreter, in `tests/test.sh`), `examples/learn/25-closures.zc` (the guide), and the full suite (604 checks, 0 failed), with the fixpoint at 230551 words.

what closures still don't do: captures are by value, a closure can't be handed to a c function as a callback, and a closure passed directly to a parameter that isn't `.d` is rejected by the analyzer as an owned object, the same as any new object.