aboutsummaryrefslogtreecommitdiff
path: root/docs/history/52-closures
diff options
context:
space:
mode:
authorGravatar Moon Flower <moonflower@elhenney.local> 2026-10-12 08:46:23 +0330
committerGravatar Moon Flower <moonflower@elhenney.local> 2026-10-12 08:46:23 +0330
commitecc350ca5c2eb50be8309c5f14f8bf0d87db9a02 (patch)
tree70e0af76a1b13affff7c6cc8aac7b3e6ef960478 /docs/history/52-closures
a
Diffstat (limited to 'docs/history/52-closures')
-rw-r--r--docs/history/52-closures/notes.md14
1 files changed, 14 insertions, 0 deletions
diff --git a/docs/history/52-closures/notes.md b/docs/history/52-closures/notes.md
new file mode 100644
index 0000000..335923e
--- /dev/null
+++ b/docs/history/52-closures/notes.md
@@ -0,0 +1,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.