aboutsummaryrefslogtreecommitdiff
path: root/docs/history/10-zc/notes.md
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/10-zc/notes.md
a
Diffstat (limited to 'docs/history/10-zc/notes.md')
-rw-r--r--docs/history/10-zc/notes.md37
1 files changed, 37 insertions, 0 deletions
diff --git a/docs/history/10-zc/notes.md b/docs/history/10-zc/notes.md
new file mode 100644
index 0000000..96baec2
--- /dev/null
+++ b/docs/history/10-zc/notes.md
@@ -0,0 +1,37 @@
+# zc: the c-like genome, u m d and the collector
+
+code/ next to this file is the tree as shipped at the end of this stage (tinyvm-zc.zip), with its own README.
+
+## message 10
+
+> we're gonna make this thing cooler. make the syntax C-like whilst still keeping the forth capabilities like super-homiconicity and the likes, add explicit and automatic gc (use a fast approach) and memory management that looks like this:
+> every heap object has a classifier u m d, up middle down. up means the object will die at the scope above (becomes m when returned to the parent scope, and it must be returned and cannot be discarded). m means it must be used here and can be passed down (but once it's recasted as u or d it can't be casted back to m in this scope). d means the variable is passed down, and its lifetime ends after it's given for the first time to a scope lower than the current one.
+> ask me questions to clarify this approach, then add it to the code and also add a simple static analyzer which checks these lifetimes
+
+my answers to the clarifying questions, exactly:
+
+> scope: every { } block
+>
+> lending an m object to a callee: borrow, no escape (Recommended)
+>
+> storing a heap object inside another object or a global: container gets ownership. putting a value inside a container requires its umd to match the parent, and from then on, the umd for that is also inherited from the parent (as in if a parent m is casted to d, so is the child heap object)
+>
+> gc: free lists + mark-sweep (Recommended)
+>
+> where the compiler lives: resident in vm code. bootstrap it step by step, by writing a c-like in core.c and then rewriting the compiler inside the c-like. also bring back llvm if you think it'll make your job easier
+>
+> homoiconic features: parse words, quoted code blocks, inline stack code, patchable compiler tables
+>
+> how an inner block hands a u object up: expression and assign, both
+>
+> when the analyzer runs: inside the compiler but can be turned off if the code requests it
+
+**summary:** the genome is now zc, a typeless c-like language, described above. stage 0 is `zc0.c` (kept as its own file next to core.c rather than inside it, so the runtime still has one native file), and the resident compiler is `src/compiler.zc` plus `src/rt.zc`, which reached a byte-identical fixpoint compiling itself. llvm wasn't brought back, since the target is the vm itself. memory went to 1m words, and core.c gained an interpreter for non-arm64 hosts. calls i made without asking: tags go on signatures (`fn f(m a, d b) -> u`) and recasts are `x as u` / `x as d`; a d object touched inside an inner block moves into that block; storing into a borrowed object, a global or untracked memory needs `as d`; handing a u up by assignment only reaches the directly enclosing block; unchecked code gives its objects to the collector. the old asm genome moved to `legacy/`.
+
+## working notes
+
+before asking anything i restated the model so it could be corrected early: m is owned here, lent freely and freed at the scope end; d is a move to the first lower scope it touches; u is a return obligation that arrives as m above; recasts only go away from m. the answers settled scopes (every block), lending (borrow, no escape), containment (tags must match and children inherit), the collector (free lists plus mark-sweep), where the compiler lives (resident, bootstrapped from c), the homoiconic features (all four), how blocks hand u up (value and assignment) and the analyzer (on, with an off switch).
+
+calls made without asking: memory grew to 1m words; core.c gained a plain interpreter for non-arm64 hosts; the language is typeless like b; tags went on signatures (`m p`, `d p`, `-> u`) with `x as u` casts; storing into globals or untracked memory needs d and hands the object to the collector; unchecked code is collector-managed.
+
+the bootstrap went zc0 (c) -> g0 -> g1 -> g2 and g1 == g2 on the first self-compile. things the analyzer caught in its own runtime on the way: puts walking a borrowed pointer with s++, wcopy returning a borrowed pointer, and the whole compiler source getting cut short by a backtick inside an error message (the backtick ends the source). the first round of rejection tests found one real gap, an m object unused before an early return, fixed with a path-independent "owned but never used" check, and one wrong test, where touching a d object in an else block moved it into that block, exactly as the rules say.