plans: briefings + roadmaps for lua, prolog, forth, erlang, haskell
Five new guest-language plans mirroring the js-on-sx / hs-loop pattern, each with a phased roadmap (Progress log + Blockers), a self-contained agent briefing for respawning a long-lived loop, and a shared restore-all.sh that snapshots state across all seven language loops. Briefings bake in the lessons from today's stall debugging: never call sx_build (600s watchdog), only touch lib/<lang>/** + own plan file, commit every feature, update Progress log on each commit, route shared-file issues to Blockers rather than fixing them. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
75
plans/agent-briefings/erlang-loop.md
Normal file
75
plans/agent-briefings/erlang-loop.md
Normal file
@@ -0,0 +1,75 @@
|
||||
# erlang-on-sx loop agent (single agent, queue-driven)
|
||||
|
||||
Role: iterates `plans/erlang-on-sx.md` forever. Actors + mailboxes + selective receive on delimited continuations. The million-process ring benchmark is the headline showcase.
|
||||
|
||||
```
|
||||
description: erlang-on-sx queue loop
|
||||
subagent_type: general-purpose
|
||||
run_in_background: true
|
||||
isolation: worktree
|
||||
```
|
||||
|
||||
## Prompt
|
||||
|
||||
You are the sole background agent working `/root/rose-ash/plans/erlang-on-sx.md`. Isolated worktree, forever, one commit per feature. Never push.
|
||||
|
||||
## Restart baseline — check before iterating
|
||||
|
||||
1. Read `plans/erlang-on-sx.md` — roadmap + Progress log.
|
||||
2. `ls lib/erlang/` — pick up from the most advanced file.
|
||||
3. If `lib/erlang/tests/*.sx` exist, run them. Green before new work.
|
||||
4. If `lib/erlang/scoreboard.md` exists, that's your baseline.
|
||||
|
||||
## The queue
|
||||
|
||||
Phase order per `plans/erlang-on-sx.md`:
|
||||
|
||||
- **Phase 1** — tokenizer + parser (atoms, vars, tuples, lists, binaries, clauses with patterns + guards)
|
||||
- **Phase 2** — sequential eval + pattern matching + guards + core BIFs (`length`, `hd`, `tl`, `element`, `lists:map`, `io:format`)
|
||||
- **Phase 3** — **THE SHOWCASE**: scheduler + processes + mailboxes + `spawn`/`!`/`receive` via delimited continuations. 5 classic programs (ring, ping_pong, bank, echo, fib_server) green. Million-process ring benchmark works.
|
||||
- **Phase 4** — links, monitors, exit signals, `try/catch`
|
||||
- **Phase 5** — modules + `M:F(...)` cross-module calls + `gen_server` + `supervisor` + registered processes
|
||||
- **Phase 6** — list comprehensions + binary pattern matching + ETS-lite + drive corpus to 200+
|
||||
|
||||
Within a phase, pick the checkbox that unlocks the most tests per effort.
|
||||
|
||||
Every iteration: implement → test → commit → tick `[ ]` → Progress log → next.
|
||||
|
||||
## Ground rules (hard)
|
||||
|
||||
- **Scope:** only `lib/erlang/**` and `plans/erlang-on-sx.md`. Do **not** edit `spec/`, `hosts/`, `shared/`, other `lib/<lang>/` dirs, `lib/stdlib.sx`, or `lib/` root. Erlang primitives go in `lib/erlang/runtime.sx`.
|
||||
- **NEVER call `sx_build`.** 600s watchdog. If sx_server binary broken → Blockers entry, stop.
|
||||
- **Shared-file issues** → plan's Blockers with minimal repro.
|
||||
- **Delimited continuations** are in `lib/callcc.sx` + `spec/evaluator.sx` Step 5. `sx_summarise` spec/evaluator.sx first — 2300+ lines.
|
||||
- **SX files:** `sx-tree` MCP tools ONLY. `sx_validate` after edits.
|
||||
- **Worktree:** commit locally. Never push. Never touch `main`.
|
||||
- **Commit granularity:** one feature per commit.
|
||||
- **Plan file:** update Progress log + tick boxes every commit.
|
||||
|
||||
## Erlang-specific gotchas
|
||||
|
||||
- **Process** = record with `{pid, mailbox, state, continuation, links, monitors, trap_exit?}`. Scheduler queue is a list of runnable pids.
|
||||
- **`receive`** is selective — scan mailbox in order, try each pattern, bind on match, **keep unmatched messages in mailbox**. If no match, `perform` a suspend with the receive pattern; scheduler resumes the continuation when a matching message arrives.
|
||||
- **`after N -> ...`** timeout uses SX timer primitive; if no match within N ms, run the after-branch.
|
||||
- **Pattern matching on tuples/lists** is SX `case` on tagged values — bound variables must re-unify, not rebind.
|
||||
- **Guards are pure** — compile-time check that no side-effecting calls appear.
|
||||
- **Immutable data** — no in-place mutation; sends copy.
|
||||
- Atoms are interned strings.
|
||||
- Don't go near the preprocessor (`-define`, `-ifdef`). Out of scope.
|
||||
- Test corpus is custom (not BEAM conformance). Write your own plus classic programs in `lib/erlang/tests/programs/`.
|
||||
|
||||
## General gotchas (all loops)
|
||||
|
||||
- SX `do` = R7RS iteration. Use `begin` for multi-expr sequences.
|
||||
- `cond`/`when`/`let` clauses evaluate only the last expr.
|
||||
- `type-of` on user fn returns `"lambda"`.
|
||||
- Shell heredoc `||` gets eaten — escape or use `case`.
|
||||
|
||||
## Style
|
||||
|
||||
- No comments in `.sx` unless non-obvious.
|
||||
- No new planning docs — update `plans/erlang-on-sx.md` inline.
|
||||
- Short, factual commit messages (`erlang: spawn/1 + basic scheduler (+5)`).
|
||||
- One feature per iteration. Commit. Log. Next.
|
||||
|
||||
Go. Read the plan; find first `[ ]`; implement.
|
||||
71
plans/agent-briefings/forth-loop.md
Normal file
71
plans/agent-briefings/forth-loop.md
Normal file
@@ -0,0 +1,71 @@
|
||||
# forth-on-sx loop agent (single agent, queue-driven)
|
||||
|
||||
Role: iterates `plans/forth-on-sx.md` forever. ANS-Forth 1994, Hayes Core conformance is the north star.
|
||||
|
||||
```
|
||||
description: forth-on-sx queue loop
|
||||
subagent_type: general-purpose
|
||||
run_in_background: true
|
||||
isolation: worktree
|
||||
```
|
||||
|
||||
## Prompt
|
||||
|
||||
You are the sole background agent working `/root/rose-ash/plans/forth-on-sx.md`. Isolated worktree, forever, one commit per feature. Never push.
|
||||
|
||||
## Restart baseline — check before iterating
|
||||
|
||||
1. Read `plans/forth-on-sx.md` — roadmap + Progress log.
|
||||
2. `ls lib/forth/` — pick up from the most advanced file.
|
||||
3. If `lib/forth/tests/*.sx` exist, run them. Green before new work.
|
||||
4. If `lib/forth/scoreboard.md` exists, that's your baseline; attack worst failure mode.
|
||||
|
||||
## The queue
|
||||
|
||||
Phase order per `plans/forth-on-sx.md`:
|
||||
|
||||
- **Phase 1** — reader + interpret mode + core stack/arith/cmp/logic/IO words
|
||||
- **Phase 2** — colon definitions + compile mode + `VARIABLE`/`CONSTANT`/`VALUE`/`@`/`!`
|
||||
- **Phase 3** — control flow (`IF`/`ELSE`/`THEN`, `BEGIN`/`UNTIL`/`WHILE`/`REPEAT`/`AGAIN`, `DO`/`LOOP`, return stack) + vendor Hayes suite + first scoreboard
|
||||
- **Phase 4** — strings, `BASE` manipulation, more Core words
|
||||
- **Phase 5** — Core Extension, File/String word sets, drive to 100% Hayes
|
||||
- **Phase 6** — inline primitive compile + TCO colon-def endings + JIT cooperation
|
||||
|
||||
Within a phase, pick the checkbox that gets the most Hayes tests passing per unit of effort.
|
||||
|
||||
Every iteration: implement → test → commit → tick `[ ]` → append Progress log → next.
|
||||
|
||||
## Ground rules (hard)
|
||||
|
||||
- **Scope:** only `lib/forth/**` and `plans/forth-on-sx.md`. Do **not** edit `spec/`, `hosts/`, `shared/`, other `lib/<lang>/` dirs, `lib/stdlib.sx`, or `lib/` root. Forth primitives go in `lib/forth/runtime.sx`.
|
||||
- **NEVER call `sx_build`.** 600s watchdog. If sx_server binary broken → Blockers entry, stop.
|
||||
- **Shared-file issues** → plan's Blockers with minimal repro.
|
||||
- **SX files:** `sx-tree` MCP tools ONLY. `sx_validate` after edits.
|
||||
- **Worktree:** commit locally. Never push. Never touch `main`.
|
||||
- **Commit granularity:** one feature per commit.
|
||||
- **Plan file:** update Progress log + tick boxes every commit.
|
||||
|
||||
## Forth-specific gotchas
|
||||
|
||||
- **Case-insensitive** — lowercase on lookup.
|
||||
- Compile mode flag lives on interpreter state; `:` sets, `;` clears.
|
||||
- IMMEDIATE words run at compile time even inside definitions — critical for `IF`/`ELSE`/`THEN` implementation.
|
||||
- Return stack is separate from data stack. `>R`/`R>` move between them.
|
||||
- `BASE` is a user-manipulable variable; number parsing must respect it.
|
||||
- Colon-def body = SX lambda. Run on the CEK, inherit TCO.
|
||||
- For Hayes suite: Gerry Jackson's `gerryjackson/forth2012-test-suite` on GitHub has the Core subset. Vendor `src/core.fth` + `src/tester.fr`. Document which source in Progress log.
|
||||
|
||||
## General gotchas (all loops)
|
||||
|
||||
- SX `do` = R7RS iteration. Use `begin` for multi-expr sequences.
|
||||
- `cond`/`when`/`let` clauses evaluate only the last expr.
|
||||
- Shell heredoc `||` gets eaten — escape or use `case`.
|
||||
|
||||
## Style
|
||||
|
||||
- No comments in `.sx` unless non-obvious.
|
||||
- No new planning docs — update `plans/forth-on-sx.md` inline.
|
||||
- Short, factual commit messages (`forth: DO/LOOP + return stack (+12)`).
|
||||
- One feature per iteration. Commit. Log. Next.
|
||||
|
||||
Go. Read the plan; find first `[ ]`; implement.
|
||||
76
plans/agent-briefings/haskell-loop.md
Normal file
76
plans/agent-briefings/haskell-loop.md
Normal file
@@ -0,0 +1,76 @@
|
||||
# haskell-on-sx loop agent (single agent, queue-driven)
|
||||
|
||||
Role: iterates `plans/haskell-on-sx.md` forever. Mini-Haskell 98 with real laziness (SX thunks are first-class). Phases 1-3 are untyped — laziness + ADTs first; HM inference is phase 4.
|
||||
|
||||
```
|
||||
description: haskell-on-sx queue loop
|
||||
subagent_type: general-purpose
|
||||
run_in_background: true
|
||||
isolation: worktree
|
||||
```
|
||||
|
||||
## Prompt
|
||||
|
||||
You are the sole background agent working `/root/rose-ash/plans/haskell-on-sx.md`. Isolated worktree, forever, one commit per feature. Never push.
|
||||
|
||||
**Note:** there's an existing `/root/rose-ash/sx-haskell/` directory (~25 M). Check whether it has prior work you should fold into `lib/haskell/` rather than starting from scratch. Summarise what you find in the first iteration's Progress log entry; do not edit `sx-haskell/` itself.
|
||||
|
||||
## Restart baseline — check before iterating
|
||||
|
||||
1. Read `plans/haskell-on-sx.md` — roadmap + Progress log.
|
||||
2. First-run only: peek at `/root/rose-ash/sx-haskell/` — does any of it belong in `lib/haskell/`? Report in Progress log. Don't edit sx-haskell/.
|
||||
3. `ls lib/haskell/` — pick up from the most advanced file.
|
||||
4. Run `lib/haskell/tests/*.sx` if they exist. Green before new work.
|
||||
5. If `lib/haskell/scoreboard.md` exists, that's your baseline.
|
||||
|
||||
## The queue
|
||||
|
||||
Phase order per `plans/haskell-on-sx.md`:
|
||||
|
||||
- **Phase 1** — tokenizer + parser + **layout rule** (indentation-sensitive, painful but required per Haskell 98 §10.3)
|
||||
- **Phase 2** — desugar + eager eval + ADTs (`data` declarations, constructor tagging, pattern matching). Still untyped.
|
||||
- **Phase 3** — **laziness**: thunk-wrap every application arg, `force` = WHNF, pattern match forces scrutinee. Classic programs (infinite Fibonacci, sieve of Eratosthenes, quicksort, n-queens, expression calculator) green.
|
||||
- **Phase 4** — Hindley-Milner type inference (Algorithm W, let-polymorphism, type-sig checking)
|
||||
- **Phase 5** — typeclasses (dictionary passing, Eq/Ord/Show/Num/Functor/Monad/Applicative, `deriving`)
|
||||
- **Phase 6** — real `IO` monad backed by `perform`/`resume`, full Prelude, drive corpus to 150+
|
||||
|
||||
Within a phase, pick the checkbox with the best tests-per-effort ratio.
|
||||
|
||||
Every iteration: implement → test → commit → tick `[ ]` → Progress log → next.
|
||||
|
||||
## Ground rules (hard)
|
||||
|
||||
- **Scope:** only `lib/haskell/**` and `plans/haskell-on-sx.md`. Do **not** edit `spec/`, `hosts/`, `shared/`, other `lib/<lang>/` dirs, `lib/stdlib.sx`, `lib/` root, or `sx-haskell/`. Haskell primitives go in `lib/haskell/runtime.sx`.
|
||||
- **NEVER call `sx_build`.** 600s watchdog. If sx_server binary broken → Blockers entry, stop.
|
||||
- **Shared-file issues** → plan's Blockers with minimal repro.
|
||||
- **SX thunks** (`make-thunk`, force on use) are already in the trampolining evaluator — reuse. Don't invent your own thunk type.
|
||||
- **SX files:** `sx-tree` MCP tools ONLY. `sx_validate` after edits.
|
||||
- **Worktree:** commit locally. Never push. Never touch `main`.
|
||||
- **Commit granularity:** one feature per commit.
|
||||
- **Plan file:** update Progress log + tick boxes every commit.
|
||||
|
||||
## Haskell-specific gotchas
|
||||
|
||||
- **Layout rule is the hard bit of parsing** — you need a lexer-parser feedback loop that inserts virtual `{`, `;`, `}` based on indentation. Budget proportionally.
|
||||
- **Every application arg is a thunk** — compiling `f x y` to `(f (thunk x) (thunk y))` not `(f x y)`. Pattern-match forces.
|
||||
- **ADT representation:** tagged list, e.g. `data Maybe a = Nothing | Just a` → constructors are `(:Nothing)` (0-ary) and `(:Just <thunk>)` (1-ary). Pattern match on the head symbol.
|
||||
- **Let-polymorphism** (phase 4): generalise at let-binding boundaries only, not at lambda.
|
||||
- **Typeclass dictionaries** (phase 5): each class is a record type; each instance builds the record; method call = project + apply.
|
||||
- **`IO`** (phase 6): internally `World -> (a, World)` but in practice backed by `perform`/`resume` for real side effects. Desugar `do`-notation to `>>=`.
|
||||
- **Out of scope:** GHC extensions. No `DataKinds`, `GADTs`, `TypeFamilies`, `TemplateHaskell`. Stick to Haskell 98.
|
||||
|
||||
## General gotchas (all loops)
|
||||
|
||||
- SX `do` = R7RS iteration. Use `begin` for multi-expr sequences.
|
||||
- `cond`/`when`/`let` clauses evaluate only the last expr.
|
||||
- `type-of` on user fn returns `"lambda"`.
|
||||
- Shell heredoc `||` gets eaten — escape or use `case`.
|
||||
|
||||
## Style
|
||||
|
||||
- No comments in `.sx` unless non-obvious.
|
||||
- No new planning docs — update `plans/haskell-on-sx.md` inline.
|
||||
- Short, factual commit messages (`haskell: layout rule + first parse (+10)`).
|
||||
- One feature per iteration. Commit. Log. Next.
|
||||
|
||||
Go. Read the plan; (first run only) peek at sx-haskell/ and report; find first `[ ]`; implement.
|
||||
75
plans/agent-briefings/lua-loop.md
Normal file
75
plans/agent-briefings/lua-loop.md
Normal file
@@ -0,0 +1,75 @@
|
||||
# lua-on-sx loop agent (single agent, queue-driven)
|
||||
|
||||
Role: iterates `plans/lua-on-sx.md` forever. One feature per commit. Scoreboard-driven once phase 3 is done: PUC-Rio 5.1.5 Core pass-rate is the north star.
|
||||
|
||||
```
|
||||
description: lua-on-sx queue loop
|
||||
subagent_type: general-purpose
|
||||
run_in_background: true
|
||||
isolation: worktree
|
||||
```
|
||||
|
||||
## Prompt
|
||||
|
||||
You are the sole background agent working `/root/rose-ash/plans/lua-on-sx.md`. You run in an isolated git worktree. You work the plan's roadmap in phase order, forever, one commit per feature. You never push.
|
||||
|
||||
## Restart baseline — check before iterating
|
||||
|
||||
1. Read `plans/lua-on-sx.md` — the roadmap tells you what's done (`[x]`) and what's next (`[ ]`). The Progress log (newest-first) is your memory across crashes.
|
||||
2. `ls lib/lua/` — pick up from the most advanced file that exists.
|
||||
3. `bash lib/lua/conformance.sh` if it exists — current scoreboard is your starting number. If not yet created, that's phase 3 work.
|
||||
4. If `lib/lua/tests/` exists, run the SX unit tests. They must be green before you start new work.
|
||||
|
||||
## The queue
|
||||
|
||||
Work in phase order per `plans/lua-on-sx.md`. At the top level:
|
||||
|
||||
- **Phase 1** — tokenizer + parser (small snippets green first)
|
||||
- **Phase 2** — transpile arithmetic + control flow
|
||||
- **Phase 3** — tables + functions + first PUC-Rio scoreboard
|
||||
- **Phase 4** — metatables + `pcall`/`error` + generic `for`
|
||||
- **Phase 5** — coroutines via `perform`/`cek-resume` (showcase)
|
||||
- **Phase 6** — string/math/table/io stdlib
|
||||
- **Phase 7** — `require`/modules + drive conformance to 100%
|
||||
|
||||
Within a phase, pick the checkbox that unlocks the most tests per effort. Once the scoreboard exists, re-read `lib/lua/scoreboard.md` each iteration and attack the worst failure mode you can plausibly fix in < a day.
|
||||
|
||||
Every iteration:
|
||||
1. Implement
|
||||
2. Add/update tests in `lib/lua/tests/`
|
||||
3. Re-run conformance if it exists, regenerate scoreboard
|
||||
4. Commit with a short factual message (e.g. `lua: table constructor hash-part (+17)`)
|
||||
5. Tick the matching `[ ]` → `[x]` in `plans/lua-on-sx.md`
|
||||
6. Append a one-line dated bullet to the plan's Progress log (newest first)
|
||||
7. Move to next
|
||||
|
||||
## Ground rules (hard)
|
||||
|
||||
- **Scope:** only `lib/lua/**` and `plans/lua-on-sx.md`. Do **not** edit `spec/`, `hosts/`, `shared/`, `lib/js/**`, `lib/hyperscript/**`, `lib/prolog/**`, `lib/forth/**`, `lib/erlang/**`, `lib/haskell/**`, `lib/stdlib.sx`, or anything in `lib/` root. Lua primitives go in `lib/lua/runtime.sx`.
|
||||
- **NEVER call `sx_build`.** The 600s agent watchdog will kill you before an OCaml build finishes. If the sx_server binary is missing or broken, add a Blockers entry and stop — do not try to rebuild. Use the binary at `hosts/ocaml/_build/default/bin/sx_server.exe` if present.
|
||||
- **Shared-file issues** → plan's Blockers section with a minimal repro. Don't fix them.
|
||||
- **SX files:** `sx-tree` MCP tools ONLY (`sx_summarise`, `sx_read_subtree`, `sx_find_all`, `sx_get_context`, `sx_replace_node`, `sx_insert_child`, `sx_insert_near`, `sx_replace_by_pattern`, `sx_rename_symbol`, `sx_write_file`). Run `sx_validate` after edits. Never `Edit`/`Read`/`Write` on `.sx` files — a hook blocks it.
|
||||
- **Shell, Python, Markdown, JSON, Lua files:** edit normally.
|
||||
- **Worktree:** commit locally. Never push. Never touch `main`.
|
||||
- **Commit granularity:** one feature per commit. If partial, still commit — don't hoard.
|
||||
- **Tests:** never regress. If a feature needs a larger refactor, split into commits each green.
|
||||
- **Plan file:** update Progress log + tick boxes every commit. Don't rewrite history.
|
||||
- **If blocked** for two iterations on the same issue, add to Blockers and move on.
|
||||
|
||||
## Gotchas already learned (all loops)
|
||||
|
||||
- SX `do` is R7RS iteration — **use `begin`** for multi-expr sequences.
|
||||
- `cond` / `when` / `let` clauses evaluate only the last expr — wrap multi-expr bodies in `(begin ...)`.
|
||||
- `type-of` on user fn returns `"lambda"`. `type-of` on builtin returns `"function"`.
|
||||
- `&rest args` is SX varargs. `make-symbol` builds identifier symbols.
|
||||
- Shell heredoc `||` gets eaten by bash — escape or use `case`.
|
||||
- Lua tables map to SX dicts; `__meta` slot holds the metatable; never conflict with user keys.
|
||||
|
||||
## Style
|
||||
|
||||
- No comments in `.sx` unless non-obvious.
|
||||
- No new planning docs — update `plans/lua-on-sx.md` inline.
|
||||
- Short, factual commit messages.
|
||||
- One feature per iteration. Commit. Log. Next.
|
||||
|
||||
Go. Start by reading the plan to find the first unchecked `[ ]`, then implement it.
|
||||
74
plans/agent-briefings/prolog-loop.md
Normal file
74
plans/agent-briefings/prolog-loop.md
Normal file
@@ -0,0 +1,74 @@
|
||||
# prolog-on-sx loop agent (single agent, queue-driven)
|
||||
|
||||
Role: iterates `plans/prolog-on-sx.md` forever. Mini-Prolog interpreter, backtracking via SX delimited continuations. One feature per commit.
|
||||
|
||||
```
|
||||
description: prolog-on-sx queue loop
|
||||
subagent_type: general-purpose
|
||||
run_in_background: true
|
||||
isolation: worktree
|
||||
```
|
||||
|
||||
## Prompt
|
||||
|
||||
You are the sole background agent working `/root/rose-ash/plans/prolog-on-sx.md`. You run in an isolated git worktree. You work the plan's roadmap forever, one commit per feature. You never push.
|
||||
|
||||
## Restart baseline — check before iterating
|
||||
|
||||
1. Read `plans/prolog-on-sx.md` — roadmap + Progress log tell you where you are.
|
||||
2. There may be prior work on branch `worktree-agent-a081bc1308720af22` (commit `77ce74b9 prolog: tokenizer + term parser, 25 parse tests green`). If you're on that branch, phase 1 is done. If you're on a fresh branch, start phase 1.
|
||||
3. `ls lib/prolog/` — pick up from the most advanced file that exists.
|
||||
4. Run `lib/prolog/tests/*.sx` if they exist. Must be green before new work.
|
||||
5. If `lib/prolog/scoreboard.md` exists, that's your starting number.
|
||||
|
||||
## The queue
|
||||
|
||||
Phase order per `plans/prolog-on-sx.md`:
|
||||
|
||||
- **Phase 1** — tokenizer + term parser (no operator table) — *may already be done*
|
||||
- **Phase 2** — unification + trail (isolated module, 30+ tests)
|
||||
- **Phase 3** — clause DB + DFS solver with delimited-continuation backtracking + cut + 5 classic programs green
|
||||
- **Phase 4** — operator table + `assert`/`retract` + `findall`/`bagof`/`setof` + `copy_term`/`functor`/`arg`/`=..`
|
||||
- **Phase 5** — Hyperscript integration (`prolog-query` primitive + DSL)
|
||||
- **Phase 6** — vendor Hirst's ISO conformance tests, drive scoreboard to 200+
|
||||
- **Phase 7** — compile clauses to SX (optional speed phase)
|
||||
|
||||
Within a phase, pick the checkbox with the best tests-per-effort ratio. Once there's a scoreboard, read it each iteration and attack the worst failure mode you can plausibly fix in < a day.
|
||||
|
||||
Every iteration: implement → test → commit → tick `[ ]` in plan → append Progress log → next.
|
||||
|
||||
## Ground rules (hard)
|
||||
|
||||
- **Scope:** only `lib/prolog/**` and `plans/prolog-on-sx.md`. Do **not** edit `spec/`, `hosts/`, `shared/`, other `lib/<lang>/` dirs, `lib/stdlib.sx`, or `lib/` root. Prolog primitives go in `lib/prolog/runtime.sx`.
|
||||
- **NEVER call `sx_build`.** 600s watchdog will kill you before OCaml finishes. If sx_server binary is broken, add Blockers entry and stop.
|
||||
- **Shared-file issues** → plan's Blockers section with a minimal repro. Don't fix them.
|
||||
- **Delimited continuations** are in `lib/callcc.sx` + `spec/evaluator.sx` Step 5 (IO suspension via `perform`/`cek-resume`). `sx_summarise` spec/evaluator.sx first — it's 2300+ lines.
|
||||
- **SX files:** `sx-tree` MCP tools ONLY. `sx_validate` after edits. Never `Edit`/`Read`/`Write` on `.sx`.
|
||||
- **Worktree:** commit locally. Never push. Never touch `main`.
|
||||
- **Commit granularity:** one feature per commit.
|
||||
- **Plan file:** update Progress log + tick boxes every commit.
|
||||
- **If blocked** for two iterations on the same issue, add to Blockers and move on.
|
||||
|
||||
## Prolog-specific gotchas
|
||||
|
||||
- Variables must have mutable binding slots (SX dicts with a ref, or an explicit `make-var` primitive that returns something unifiable).
|
||||
- Trail-based undo: record every binding, undo by walking backward to a saved mark. Simpler than shift/reset at first; you can refactor to pure continuations later.
|
||||
- Cut (`!`) needs a cut barrier at the enclosing goal entry. Implement as a continuation prompt tag.
|
||||
- Classic list cons: pick ONE representation (`(. H T)` vs pair-dict) and document it in the plan's architecture sketch. Don't mix.
|
||||
- `is/2` evaluates arithmetic on already-ground terms — fail if unbound.
|
||||
|
||||
## General gotchas (all loops)
|
||||
|
||||
- SX `do` = R7RS iteration. Use `begin` for multi-expr sequences.
|
||||
- `cond`/`when`/`let` clauses evaluate only the last expr.
|
||||
- `sx_validate` after every structural edit.
|
||||
- Shell heredoc `||` gets eaten — escape or use `case`.
|
||||
|
||||
## Style
|
||||
|
||||
- No comments in `.sx` unless non-obvious.
|
||||
- No new planning docs — update `plans/prolog-on-sx.md` inline.
|
||||
- Short, factual commit messages (`prolog: assert/1 + retract/1 (+8)`).
|
||||
- One feature per iteration. Commit. Log. Next.
|
||||
|
||||
Go. Start by reading the plan; find the first unchecked `[ ]`; implement it.
|
||||
105
plans/erlang-on-sx.md
Normal file
105
plans/erlang-on-sx.md
Normal file
@@ -0,0 +1,105 @@
|
||||
# Erlang-on-SX: actors on delimited continuations
|
||||
|
||||
The headline showcase for the SX runtime. Erlang is built around the **one** primitive — lightweight processes with mailboxes and selective receive — that delimited continuations implement natively. Most Erlang implementations ship a whole VM (BEAM) for this; on SX each process is a pair of continuations and the scheduler is ~50 lines of SX.
|
||||
|
||||
End-state goal: spawn a million processes, run the classic **ring benchmark**, plus a mini gen_server OTP subset and a test corpus of ~150 programs.
|
||||
|
||||
## Scope decisions (defaults — override by editing before we spawn)
|
||||
|
||||
- **Syntax:** Erlang/OTP 26 subset. No preprocessor, no parse transforms.
|
||||
- **Conformance:** not BEAM-compat. "Looks like Erlang, runs like Erlang, not byte-compatible." We care about semantics, not BEAM bug-for-bug.
|
||||
- **Test corpus:** custom — ring, ping-pong, fibonacci-server, bank-account-server, echo-server, plus ~100 hand-written tests for patterns/guards/BIFs. No ISO Common Test.
|
||||
- **Binaries:** basic bytes-lists only; full binary pattern matching deferred.
|
||||
- **Hot code reload, distribution, NIFs:** out of scope entirely.
|
||||
|
||||
## Ground rules
|
||||
|
||||
- **Scope:** only touch `lib/erlang/**` and `plans/erlang-on-sx.md`. Don't edit `spec/`, `hosts/`, `shared/`, `lib/js/**`, `lib/hyperscript/**`, `lib/lua/**`, `lib/prolog/**`, `lib/forth/**`, `lib/haskell/**`, `lib/stdlib.sx`, or `lib/` root. Erlang primitives go in `lib/erlang/runtime.sx`.
|
||||
- **SX files:** use `sx-tree` MCP tools only.
|
||||
- **Commits:** one feature per commit. Keep `## Progress log` updated and tick roadmap boxes.
|
||||
|
||||
## Architecture sketch
|
||||
|
||||
```
|
||||
Erlang source
|
||||
│
|
||||
▼
|
||||
lib/erlang/tokenizer.sx — atoms, vars, tuples, lists, binaries, operators
|
||||
│
|
||||
▼
|
||||
lib/erlang/parser.sx — AST: modules, functions with clauses, patterns, guards
|
||||
│
|
||||
▼
|
||||
lib/erlang/transpile.sx — AST → SX AST (entry: erlang-eval-ast)
|
||||
│
|
||||
▼
|
||||
lib/erlang/runtime.sx — scheduler, processes, mailboxes, BIFs
|
||||
```
|
||||
|
||||
Core mapping:
|
||||
- **Process** = pair of delimited continuations (`on-receive`, `on-resume`) + mailbox list + pid + links
|
||||
- **Scheduler** = round-robin list of runnable processes; cooperative yield on `receive`
|
||||
- **`spawn`** = push a new process record, return its pid
|
||||
- **`send`** = append to target mailbox; if target is blocked on receive, resume its continuation
|
||||
- **`receive`** = selective — scan mailbox for first matching clause; if none, `perform` a suspend with the receive pattern; scheduler resumes when a matching message arrives
|
||||
- **Pattern matching** = SX `case` on tagged values; vars bind on match
|
||||
- **Guards** = side-effect-free predicate evaluated after unification
|
||||
- **Immutable data** = native
|
||||
- **Links / monitors / exit signals** = additional process-record fields, scheduler fires exit signals on death
|
||||
|
||||
## Roadmap
|
||||
|
||||
### Phase 1 — tokenizer + parser
|
||||
- [ ] Tokenizer: atoms (bare + single-quoted), variables (Uppercase/`_`-prefixed), numbers (int, float, `16#HEX`), strings `"..."`, chars `$c`, punct `( ) { } [ ] , ; . : :: ->`
|
||||
- [ ] Parser: module declarations, `-module`/`-export`/`-import` attributes, function clauses with head patterns + guards + body
|
||||
- [ ] Expressions: literals, vars, calls, tuples `{...}`, lists `[...|...]`, binaries `<<...>>`, `if`, `case`, `receive`, `fun`, `try/catch`, operators
|
||||
- [ ] Unit tests in `lib/erlang/tests/parse.sx`
|
||||
|
||||
### Phase 2 — sequential eval + pattern matching + BIFs
|
||||
- [ ] `erlang-eval-ast`: evaluate sequential expressions
|
||||
- [ ] Pattern matching (atoms, numbers, vars, tuples, lists, `[H|T]`, underscore, bound-var re-match)
|
||||
- [ ] Guards: `is_integer`, `is_atom`, `is_list`, `is_tuple`, comparisons, arithmetic
|
||||
- [ ] BIFs: `length/1`, `hd/1`, `tl/1`, `element/2`, `tuple_size/1`, `atom_to_list/1`, `list_to_atom/1`, `lists:map/2`, `lists:foldl/3`, `lists:reverse/1`, `io:format/1-2`
|
||||
- [ ] 30+ tests in `lib/erlang/tests/eval.sx`
|
||||
|
||||
### Phase 3 — processes + mailboxes + receive (THE SHOWCASE)
|
||||
- [ ] Scheduler in `runtime.sx`: runnable queue, pid counter, per-process state record
|
||||
- [ ] `spawn/1`, `spawn/3`, `self/0`
|
||||
- [ ] `!` (send), `receive ... end` with selective pattern matching
|
||||
- [ ] `receive ... after Ms -> ...` timeout clause (use SX timer primitive)
|
||||
- [ ] `exit/1`, basic process termination
|
||||
- [ ] Classic programs in `lib/erlang/tests/programs/`:
|
||||
- [ ] `ring.erl` — N processes in a ring, pass a token around M times
|
||||
- [ ] `ping_pong.erl` — two processes exchanging messages
|
||||
- [ ] `bank.erl` — account server (deposit/withdraw/balance)
|
||||
- [ ] `echo.erl` — minimal server
|
||||
- [ ] `fib_server.erl` — compute fib on request
|
||||
- [ ] `lib/erlang/conformance.sh` + runner, `scoreboard.json` + `scoreboard.md`
|
||||
- [ ] Target: 5/5 classic programs + 1M-process ring benchmark runs
|
||||
|
||||
### Phase 4 — links, monitors, exit signals
|
||||
- [ ] `link/1`, `unlink/1`, `monitor/2`, `demonitor/1`
|
||||
- [ ] Exit-signal propagation; trap_exit flag
|
||||
- [ ] `try/catch/of/end`
|
||||
|
||||
### Phase 5 — modules + OTP-lite
|
||||
- [ ] `-module(M).` loading, `M:F(...)` calls across modules
|
||||
- [ ] `gen_server` behaviour (the big OTP win)
|
||||
- [ ] `supervisor` (simple one-for-one)
|
||||
- [ ] Registered processes: `register/2`, `whereis/1`
|
||||
|
||||
### Phase 6 — the rest
|
||||
- [ ] List comprehensions `[X*2 || X <- L]`
|
||||
- [ ] Binary pattern matching `<<A:8, B:16>>`
|
||||
- [ ] ETS-lite (in-memory tables via SX dicts)
|
||||
- [ ] More BIFs — target 200+ test corpus green
|
||||
|
||||
## Progress log
|
||||
|
||||
_Newest first._
|
||||
|
||||
- _(not started)_
|
||||
|
||||
## Blockers
|
||||
|
||||
- _(none yet)_
|
||||
106
plans/forth-on-sx.md
Normal file
106
plans/forth-on-sx.md
Normal file
@@ -0,0 +1,106 @@
|
||||
# Forth-on-SX: stack language on the VM
|
||||
|
||||
The smallest serious second language — Forth's stack-based semantics map directly onto the SX bytecode VM (OP_DUP, OP_SWAP, OP_DROP already exist as arithmetic primitives or can be added trivially). Compile-mode / interpret-mode is the one genuinely novel piece, but it's a classic technique and small.
|
||||
|
||||
End-state goal: **passes John Hayes' ANS-Forth test suite** (the canonical Forth conformance harness — small, well-documented, targets the Core word set).
|
||||
|
||||
## Scope decisions (defaults — override)
|
||||
|
||||
- **Standard:** ANS-Forth 1994 Core word set + Core Extension. No ANS-Forth Optional word sets (File Access, Floating Point, Search Order, etc.) in the first run.
|
||||
- **Test suite:** John Hayes' "Test Suite for ANS Forth" (~250 tests, public domain, widely used).
|
||||
- **Case-sensitivity:** case-insensitive (ANS default).
|
||||
- **Number base:** support `BASE` variable, defaults to 10. Hex and binary literals (`$FF`, `%1010`) per standard.
|
||||
|
||||
## Ground rules
|
||||
|
||||
- **Scope:** only touch `lib/forth/**` and `plans/forth-on-sx.md`. No edits to `spec/`, `hosts/`, `shared/`, or other language dirs.
|
||||
- **SX files:** use `sx-tree` MCP tools only.
|
||||
- **Architecture:** reader (not tokenizer — Forth is whitespace-delimited) → interpreter → dictionary-backed compiler. The compiler emits SX AST (not bytecode directly) so we inherit the VM.
|
||||
- **Commits:** one feature per commit. Keep `## Progress log` updated.
|
||||
|
||||
## Architecture sketch
|
||||
|
||||
```
|
||||
Forth source text
|
||||
│
|
||||
▼
|
||||
lib/forth/reader.sx — whitespace-split words (that's it — no real tokenizer)
|
||||
│
|
||||
▼
|
||||
lib/forth/interpreter.sx — interpret mode: look up word in dict, execute
|
||||
│
|
||||
▼
|
||||
lib/forth/compiler.sx — compile mode (`:` opens, `;` closes): emit SX AST
|
||||
│
|
||||
▼
|
||||
lib/forth/runtime.sx — stack ops, dictionary, BASE, I/O
|
||||
│
|
||||
▼
|
||||
existing CEK / VM — runs compiled definitions natively
|
||||
```
|
||||
|
||||
Representation:
|
||||
- **Stack** = SX list, push = cons, pop = uncons
|
||||
- **Dictionary** = dict `word-name → {:kind :immediate? :body}` where kind is `:primitive` or `:colon-def`
|
||||
- **A colon definition** compiles to a thunk `(lambda () <body-as-sx-sequence>)`
|
||||
- **Compile-mode** is a flag on the interpreter state; `:` sets it, `;` clears and installs the new word
|
||||
- **IMMEDIATE** words run at compile time
|
||||
|
||||
## Roadmap
|
||||
|
||||
### Phase 1 — reader + interpret mode
|
||||
- [ ] `lib/forth/reader.sx`: whitespace-split, number parsing (base-aware)
|
||||
- [ ] `lib/forth/runtime.sx`: stack as SX list, push/pop/peek helpers
|
||||
- [ ] Core stack words: `DUP`, `DROP`, `SWAP`, `OVER`, `ROT`, `NIP`, `TUCK`, `PICK`, `ROLL`, `?DUP`, `2DUP`, `2DROP`, `2SWAP`, `2OVER`
|
||||
- [ ] Arithmetic: `+`, `-`, `*`, `/`, `MOD`, `/MOD`, `NEGATE`, `ABS`, `MIN`, `MAX`, `1+`, `1-`, `2*`, `2/`
|
||||
- [ ] Comparison: `=`, `<`, `>`, `<=`, `>=`, `0=`, `0<`, `0>`
|
||||
- [ ] Logical: `AND`, `OR`, `XOR`, `INVERT`
|
||||
- [ ] I/O: `.` (print), `.S` (show stack), `EMIT`, `CR`, `SPACE`, `SPACES`
|
||||
- [ ] Interpreter loop: read word, look up, execute, repeat
|
||||
- [ ] Unit tests in `lib/forth/tests/interp.sx`
|
||||
|
||||
### Phase 2 — colon definitions + compile mode
|
||||
- [ ] `:` opens compile mode and starts a definition
|
||||
- [ ] `;` closes it and installs into the dictionary
|
||||
- [ ] Compile mode: non-IMMEDIATE words get appended as SX references; numbers get compiled as literals; IMMEDIATE words (like `IF`) run now
|
||||
- [ ] `VARIABLE`, `CONSTANT`, `VALUE`, `TO`
|
||||
- [ ] `@` (fetch), `!` (store), `+!`
|
||||
- [ ] Compile a colon def into an SX lambda that the CEK runs directly
|
||||
- [ ] Tests: define words, call them, nest definitions
|
||||
|
||||
### Phase 3 — control flow + first Hayes tests green
|
||||
- [ ] `IF`, `ELSE`, `THEN` — compile to SX `if`
|
||||
- [ ] `BEGIN`, `UNTIL`, `WHILE`, `REPEAT`, `AGAIN` — compile to loops
|
||||
- [ ] `DO`, `LOOP`, `+LOOP`, `I`, `J`, `LEAVE` — counted loops (needs a return stack)
|
||||
- [ ] Return stack: `>R`, `R>`, `R@`, `2>R`, `2R>`, `2R@`
|
||||
- [ ] Vendor John Hayes' test suite to `lib/forth/ans-tests/`
|
||||
- [ ] `lib/forth/conformance.sh` + runner; `scoreboard.json` + `scoreboard.md`
|
||||
- [ ] Baseline: probably 30-50% Core passing after phase 3
|
||||
|
||||
### Phase 4 — strings + more Core
|
||||
- [ ] `S"`, `C"`, `."`, `TYPE`, `COUNT`, `CMOVE`, `FILL`, `BLANK`
|
||||
- [ ] `CHAR`, `[CHAR]`, `KEY`, `ACCEPT`
|
||||
- [ ] `BASE` manipulation: `DECIMAL`, `HEX`
|
||||
- [ ] `DEPTH`, `SP@`, `SP!`
|
||||
- [ ] Drive Hayes Core pass-rate up
|
||||
|
||||
### Phase 5 — Core Extension + optional word sets
|
||||
- [ ] Full Core + Core Extension
|
||||
- [ ] File Access word set (via SX IO)
|
||||
- [ ] String word set (`SLITERAL`, `COMPARE`, `SEARCH`)
|
||||
- [ ] Target: 100% Hayes Core
|
||||
|
||||
### Phase 6 — speed
|
||||
- [ ] Inline primitive calls during compile (skip dict lookup)
|
||||
- [ ] Tail-call optimise colon-def endings
|
||||
- [ ] JIT cooperation: mark compiled colon-defs as VM-eligible
|
||||
|
||||
## Progress log
|
||||
|
||||
_Newest first._
|
||||
|
||||
- _(not started)_
|
||||
|
||||
## Blockers
|
||||
|
||||
- _(none yet)_
|
||||
114
plans/haskell-on-sx.md
Normal file
114
plans/haskell-on-sx.md
Normal file
@@ -0,0 +1,114 @@
|
||||
# Haskell-on-SX: mini-Haskell with real laziness
|
||||
|
||||
Mini-Haskell is the research-paper-worthy demo. Laziness is native to the SX runtime (thunks are already a first-class type); algebraic data types map onto tagged lists; typeclasses map onto dictionary passing; IO maps onto `perform`/`resume`. Hindley-Milner inference is the one real piece of new work.
|
||||
|
||||
End-state goal: a **Haskell 98 subset** that runs the small classic programs (sieve of Eratosthenes lazy stream, fibonacci as infinite list, naive quicksort, n-queens, expression evaluator) plus a ~150-test corpus.
|
||||
|
||||
## Scope decisions (defaults — override)
|
||||
|
||||
- **Standard:** Haskell 98 subset. No GHC extensions (no `DataKinds`, no `GADTs`, no `TypeFamilies`, no `TemplateHaskell`).
|
||||
- **Phase 1-3 are untyped** — we get the evaluator right first with laziness + ADTs, then add HM inference in phase 4. This is deliberate: typing is the hard bit and will take a full phase on its own.
|
||||
- **Typeclasses:** dictionary passing, no overlap, no orphan instances. Added in phase 5.
|
||||
- **Layout rule:** yes — phase 1 implements Haskell's indentation-sensitive parsing (painful but required).
|
||||
- **Test corpus:** custom. No GHC test suite. Bundle classic programs + ~100 hand-written expression-level tests + mini Prelude tests.
|
||||
|
||||
## Ground rules
|
||||
|
||||
- **Scope:** only `lib/haskell/**` and `plans/haskell-on-sx.md`. No edits to `spec/`, `hosts/`, `shared/`, or other language dirs.
|
||||
- **SX files:** `sx-tree` MCP tools only.
|
||||
- **Architecture:** Haskell source → AST → desugared-core → SX AST → CEK. Thunks on the SX side provide laziness natively.
|
||||
- **Commits:** one feature per commit. Keep `## Progress log` updated.
|
||||
|
||||
## Architecture sketch
|
||||
|
||||
```
|
||||
Haskell source
|
||||
│
|
||||
▼
|
||||
lib/haskell/tokenizer.sx — idents, operators, layout-sensitive indentation
|
||||
│
|
||||
▼
|
||||
lib/haskell/parser.sx — AST: modules, data decls, type sigs, fn clauses, expressions
|
||||
│
|
||||
▼
|
||||
lib/haskell/desugar.sx — surface → core: case-of-case, do-notation, list comp, guards
|
||||
│
|
||||
▼
|
||||
lib/haskell/transpile.sx — core → SX AST, wrapping everything in thunks for laziness
|
||||
│
|
||||
▼
|
||||
lib/haskell/runtime.sx — force, ADT constructors, Prelude, typeclass dicts (phase 5+)
|
||||
│
|
||||
▼
|
||||
existing CEK / VM
|
||||
```
|
||||
|
||||
Key mappings:
|
||||
- **Laziness** = every function argument is an SX thunk; `force` is WHNF reduction. SX already has `make-thunk` from the trampolining evaluator — we reuse it.
|
||||
- **Pattern match** = forces the scrutinee to WHNF, then structural match on the tag
|
||||
- **ADT** = `data Maybe a = Nothing | Just a` compiles to tagged lists: `(:Nothing)` and `(:Just <thunk>)`
|
||||
- **Typeclass** = each class becomes a record type; each instance becomes a record value; each method becomes a projection; the elaborator inserts the dict at each call site (phase 5)
|
||||
- **IO** = `IO a` is a function `World -> (a, World)` internally; in practice uses `perform`/`resume` for actual side effects
|
||||
- **Layout** = offside rule; inserted virtual braces + semis during a lexer-parser feedback pass
|
||||
|
||||
## Roadmap
|
||||
|
||||
### Phase 1 — tokenizer + parser + layout rule
|
||||
- [ ] Tokenizer: reserved words, qualified names, operators, numbers (int, float, Rational later), chars/strings, comments (`--` and `{-` nested)
|
||||
- [ ] Layout algorithm: turn indentation into virtual `{`, `;`, `}` tokens per Haskell 98 §10.3
|
||||
- [ ] Parser: modules, imports (stub), top-level decls, type sigs, function clauses with patterns + guards + where-clauses, expressions with operator precedence, lambdas, `let`, `if`, `case`, `do`, list comp, sections
|
||||
- [ ] AST design modelled on GHC's HsSyn at a surface level
|
||||
- [ ] Unit tests in `lib/haskell/tests/parse.sx`
|
||||
|
||||
### Phase 2 — desugar + eager-ish eval + ADTs (untyped)
|
||||
- [ ] Desugar: guards → nested `if`s; `where` → `let`; list comp → `concatMap`-based; do-notation stays for now (desugared in phase 3)
|
||||
- [ ] `data` declarations register constructors in runtime
|
||||
- [ ] Pattern match (tag-based, value-level): atoms, vars, wildcards, constructor patterns, `as` patterns, nested
|
||||
- [ ] Evaluator (still strict internally — laziness in phase 3): `let`, `lambda`, application, `case`, literals, constructors
|
||||
- [ ] 30+ eval tests in `lib/haskell/tests/eval.sx`
|
||||
|
||||
### Phase 3 — laziness + classic programs
|
||||
- [ ] Transpile to thunk-wrapped SX: every application arg becomes `(make-thunk (lambda () <arg>))`
|
||||
- [ ] `force` = SX eval-thunk-to-WHNF primitive
|
||||
- [ ] Pattern match forces scrutinee before matching
|
||||
- [ ] Infinite structures: `repeat x`, `iterate f x`, `[1..]`, Fibonacci stream, sieve of Eratosthenes
|
||||
- [ ] `seq`, `deepseq` from Prelude
|
||||
- [ ] Do-notation for a stub `IO` monad (just threading, no real side effects yet)
|
||||
- [ ] Classic programs in `lib/haskell/tests/programs/`:
|
||||
- [ ] `fib.hs` — infinite Fibonacci stream
|
||||
- [ ] `sieve.hs` — lazy sieve of Eratosthenes
|
||||
- [ ] `quicksort.hs` — naive QS
|
||||
- [ ] `nqueens.hs`
|
||||
- [ ] `calculator.hs` — parser combinator style expression evaluator
|
||||
- [ ] `lib/haskell/conformance.sh` + runner; `scoreboard.json` + `scoreboard.md`
|
||||
- [ ] Target: 5/5 classic programs passing
|
||||
|
||||
### Phase 4 — Hindley-Milner inference
|
||||
- [ ] Algorithm W: unification + type schemes + generalisation + instantiation
|
||||
- [ ] Report type errors with meaningful positions
|
||||
- [ ] Reject untypeable programs that phase 3 was accepting
|
||||
- [ ] Type-sig checking: user writes `f :: Int -> Int`; verify
|
||||
- [ ] Let-polymorphism
|
||||
- [ ] Unit tests: inference for 50+ expressions
|
||||
|
||||
### Phase 5 — typeclasses (dictionary passing)
|
||||
- [ ] `class` / `instance` declarations
|
||||
- [ ] Dictionary-passing elaborator: inserts dict args at call sites
|
||||
- [ ] Standard classes: `Eq`, `Ord`, `Show`, `Num`, `Functor`, `Monad`, `Applicative`
|
||||
- [ ] `deriving (Eq, Show)` for ADTs
|
||||
|
||||
### Phase 6 — real IO + Prelude completion
|
||||
- [ ] Real `IO` monad backed by `perform`/`resume`
|
||||
- [ ] `putStrLn`, `getLine`, `readFile`, `writeFile`, `print`
|
||||
- [ ] Full-ish Prelude: `Maybe`, `Either`, `List` functions, `Map`-lite
|
||||
- [ ] Drive scoreboard toward 150+ passing
|
||||
|
||||
## Progress log
|
||||
|
||||
_Newest first._
|
||||
|
||||
- _(not started)_
|
||||
|
||||
## Blockers
|
||||
|
||||
- _(none yet)_
|
||||
91
plans/lua-on-sx.md
Normal file
91
plans/lua-on-sx.md
Normal file
@@ -0,0 +1,91 @@
|
||||
# Lua-on-SX: Lua 5.1 on the CEK/VM
|
||||
|
||||
Compile Lua 5.1 AST to SX AST; the existing CEK evaluator runs it. Same architecture as `plans/js-on-sx.md` — reuse SX semantics wherever they fit, only shim the Lua-specific parts (tables/metatables, `nil`/`false`-only-falsy, multi-return, coroutines via `perform`/resume).
|
||||
|
||||
End-state goal: **100% of PUC-Rio Lua 5.1.5 test suite.** Running as a long-lived background agent that drives the scoreboard up one failure-mode at a time, like `lib/js/`.
|
||||
|
||||
## Ground rules
|
||||
|
||||
- **Scope:** only touch `lib/lua/**` and `plans/lua-on-sx.md`. Do **not** edit `spec/`, `hosts/`, `shared/`, `lib/js/**`, `lib/hyperscript/**`, `lib/prolog/**`, `lib/stdlib.sx`, or anything in `lib/` root. Lua-specific primitives go in `lib/lua/runtime.sx`.
|
||||
- **Shared-file issues** go under "Blockers" below with a minimal repro; do not fix from this loop.
|
||||
- **SX files:** use `sx-tree` MCP tools only (never `Edit`/`Read`/`Write` on `.sx` files). `sx_write_file` for new files, path/pattern edits for changes.
|
||||
- **Architecture:** Lua source → Lua AST → SX AST → CEK. No standalone Lua evaluator.
|
||||
- **Commits:** one feature per commit. Keep `## Progress log` updated (dated entries, newest first) and tick boxes in the roadmap.
|
||||
|
||||
## Architecture sketch
|
||||
|
||||
```
|
||||
Lua source text
|
||||
│
|
||||
▼
|
||||
lib/lua/tokenizer.sx — numbers, strings (short + long [[…]]), idents, ops, comments
|
||||
│
|
||||
▼
|
||||
lib/lua/parser.sx — Lua AST as SX trees, e.g. (lua-for-num i a b c body)
|
||||
│
|
||||
▼
|
||||
lib/lua/transpile.sx — Lua AST → SX AST (entry: lua-eval-ast)
|
||||
│
|
||||
▼
|
||||
existing CEK / VM
|
||||
```
|
||||
|
||||
Runtime shims in `lib/lua/runtime.sx`: `lua-truthy?`, string coercion for `..`/arithmetic, table ops (array + hash part), metatable dispatch, `pcall`/`error` bridge, `string`/`math`/`table` libs.
|
||||
|
||||
## Roadmap
|
||||
|
||||
Each item: implement → tests → tick box → update progress log.
|
||||
|
||||
### Phase 1 — tokenizer + parser
|
||||
- [ ] Tokenizer: numbers (int, float, hex), strings (short + long `[[…]]`), idents, keywords, operators, comments (`--`, `--[[…]]`)
|
||||
- [ ] Parser: blocks, `local`, `if/elseif/else/end`, `while`, numeric `for`, `function`, `return`, expressions, table constructors, indexing (`.`, `[]`), calls (`f(…)`, `f:m(…)`)
|
||||
- [ ] Skip for phase 1: generic `for … in …`, goto/labels, nested varargs `...`
|
||||
- [ ] Unit tests in `lib/lua/tests/parse.sx`: source → expected AST
|
||||
|
||||
### Phase 2 — transpile: control flow + arithmetic
|
||||
- [ ] `lua-eval-ast` entry
|
||||
- [ ] Arithmetic (Lua 5.1 semantics — `/` is float)
|
||||
- [ ] Comparison + logical (short-circuit, Lua truthy)
|
||||
- [ ] `..` concat with string/number coercion
|
||||
- [ ] `if`, `while`, numeric `for`, `local`, assignment, blocks
|
||||
- [ ] 30+ eval tests in `lib/lua/tests/eval.sx`
|
||||
|
||||
### Phase 3 — tables + functions + first PUC-Rio slice
|
||||
- [ ] `function` (anon, local, top-level), closures
|
||||
- [ ] Multi-return: return as list, unpack at call sites
|
||||
- [ ] Table constructors (array + hash + computed keys)
|
||||
- [ ] Raw table access `t.k` / `t[k]` (no metatables yet)
|
||||
- [ ] Vendor PUC-Rio 5.1.5 suite to `lib/lua/lua-tests/` (just `.lua` files)
|
||||
- [ ] `lib/lua/conformance.sh` + Python runner (model on `lib/js/test262-runner.py`)
|
||||
- [ ] `scoreboard.json` + `scoreboard.md` baseline
|
||||
|
||||
### Phase 4 — metatables + error handling (next run)
|
||||
- [ ] Metatable dispatch: `__index`, `__newindex`, `__add`/`__sub`/…, `__eq`, `__lt`, `__call`, `__tostring`, `__len`
|
||||
- [ ] `pcall`/`xpcall`/`error` via handler-bind
|
||||
- [ ] Generic `for … in …`
|
||||
|
||||
### Phase 5 — coroutines (the showcase)
|
||||
- [ ] `coroutine.create`/`.resume`/`.yield`/`.status`/`.wrap` via `perform`/`cek-resume`
|
||||
|
||||
### Phase 6 — standard library
|
||||
- [ ] `string` — `format`, `sub`, `find`, `match`, `gmatch`, `gsub`, `len`, `rep`, `upper`, `lower`, `byte`, `char`
|
||||
- [ ] `math` — full surface
|
||||
- [ ] `table` — `insert`, `remove`, `concat`, `sort`, `unpack`
|
||||
- [ ] `io` — minimal stub (read/write to SX IO surface)
|
||||
- [ ] `os` — time/date subset
|
||||
|
||||
### Phase 7 — modules + full conformance
|
||||
- [ ] `require` / `package` via SX `define-library`/`import`
|
||||
- [ ] Drive PUC-Rio scoreboard to 100%
|
||||
|
||||
## Progress log
|
||||
|
||||
_Newest first. Agent appends on every commit._
|
||||
|
||||
- _(awaiting phase 1)_
|
||||
|
||||
## Blockers
|
||||
|
||||
_Shared-file issues that need someone else to fix. Minimal repro only._
|
||||
|
||||
- _(none yet)_
|
||||
97
plans/prolog-on-sx.md
Normal file
97
plans/prolog-on-sx.md
Normal file
@@ -0,0 +1,97 @@
|
||||
# Prolog-on-SX: mini-Prolog interpreter on delimited continuations
|
||||
|
||||
Horn clauses + unification + cut + arithmetic, implemented as an **interpreter** (clauses live as SX data, a SX-implemented solver walks them). Backtracking is powered by the delimited-continuations machinery in `lib/callcc.sx` + `spec/evaluator.sx` Step 5 — this is the reason Prolog fits SX well.
|
||||
|
||||
End-state goal: **200+ tests passing** (classic programs + Hirst's ISO conformance subset + Hyperscript integration suite). Long-lived background agent driving the scoreboard up.
|
||||
|
||||
## Ground rules
|
||||
|
||||
- **Scope:** only touch `lib/prolog/**` and `plans/prolog-on-sx.md`. Do **not** edit `spec/`, `hosts/`, `shared/`, `lib/js/**`, `lib/hyperscript/**`, `lib/lua/**`, `lib/stdlib.sx`, or anything in `lib/` root. Prolog primitives go in `lib/prolog/runtime.sx`.
|
||||
- **Shared-file issues** go under "Blockers" below with a minimal repro; do not fix from this loop.
|
||||
- **SX files:** use `sx-tree` MCP tools only.
|
||||
- **Architecture:** Prolog source → term AST → clause DB. Solver is SX code walking the DB; backtracking via delimited continuations, not a separate trail machine.
|
||||
- **Commits:** one feature per commit. Keep `## Progress log` updated and tick boxes.
|
||||
|
||||
## Architecture sketch
|
||||
|
||||
```
|
||||
Prolog source text
|
||||
│
|
||||
▼
|
||||
lib/prolog/tokenizer.sx — atoms, vars, numbers, punct, comments
|
||||
│
|
||||
▼
|
||||
lib/prolog/parser.sx — term AST; phase 1: f(a,b) syntax only, no operator table
|
||||
│
|
||||
▼
|
||||
lib/prolog/runtime.sx — clause DB, unify!, trail, solver (DFS + delimited-cont backtracking)
|
||||
│ built-ins: =/2, \=/2, !/0, is/2, call/1, findall/3, …
|
||||
▼
|
||||
solutions / side-effects
|
||||
```
|
||||
|
||||
Representation choices (finalise in phase 1, document here):
|
||||
- **Term:** nested SX list. Compound `(functor arg1 arg2)`. Atom = symbol. Number = number. Variable = `{:var "X" :binding <ref>}` with mutable binding slot.
|
||||
- **List:** cons-cell compound `(. H T)` or similar. `[1,2,3]` sugar desugared at parse.
|
||||
- **Clause:** `{:head <term> :body <term>}` where body is the conjunction goal.
|
||||
- **Clause DB:** dict `"functor/arity" → list of clauses`.
|
||||
|
||||
## Roadmap
|
||||
|
||||
### Phase 1 — tokenizer + term parser (no operator table)
|
||||
- [ ] Tokenizer: atoms (lowercase/quoted), variables (uppercase/`_`), numbers, strings, punct `( ) , . [ ] | ! :-`, comments (`%`, `/* */`)
|
||||
- [ ] Parser: clauses `head :- body.` and facts `head.`; terms `atom | Var | number | compound(args) | [list,sugar]`
|
||||
- [ ] **Skip for phase 1:** operator table. `X is Y + 1` must be written `is(X, '+'(Y, 1))`; `=` written `=(X, Y)`. Operators land in phase 4.
|
||||
- [ ] Unit tests in `lib/prolog/tests/parse.sx`
|
||||
|
||||
### Phase 2 — unification + trail
|
||||
- [ ] `make-var`, `walk` (follow binding chain), `prolog-unify!` (terms + trail → bool), `trail-undo-to!`
|
||||
- [ ] Occurs-check off by default, exposed as flag
|
||||
- [ ] 30+ unification tests in `lib/prolog/tests/unify.sx`: atoms, vars, compounds, lists, cyclic (no-occurs-check), mutual occurs
|
||||
|
||||
### Phase 3 — clause DB + DFS solver + cut + first classic programs
|
||||
- [ ] Clause DB: `"functor/arity" → list-of-clauses`, loader inserts
|
||||
- [ ] Solver: DFS with choice points backed by delimited continuations (`lib/callcc.sx`). On goal entry, capture; per matching clause, unify head + recurse body; on failure, undo trail, try next
|
||||
- [ ] Cut (`!`): cut barrier at current choice-point frame; collapse all up to barrier
|
||||
- [ ] Built-ins: `=/2`, `\\=/2`, `true/0`, `fail/0`, `!/0`, `,/2`, `;/2`, `->/2` inside `;`, `call/1`, `write/1`, `nl/0`
|
||||
- [ ] Arithmetic `is/2` with `+ - * / mod abs`
|
||||
- [ ] Classic programs in `lib/prolog/tests/programs/`:
|
||||
- [ ] `append.pl` — list append (with backtracking)
|
||||
- [ ] `reverse.pl` — naive reverse
|
||||
- [ ] `member.pl` — generate all solutions via backtracking
|
||||
- [ ] `nqueens.pl` — 8-queens
|
||||
- [ ] `family.pl` — facts + rules (parent/ancestor)
|
||||
- [ ] `lib/prolog/conformance.sh` + runner, `scoreboard.json` + `scoreboard.md`
|
||||
- [ ] Target: all 5 classic programs passing
|
||||
|
||||
### Phase 4 — operator table + more built-ins (next run)
|
||||
- [ ] Operator table parsing (prefix/infix/postfix, precedence, assoc)
|
||||
- [ ] `assert/1`, `asserta/1`, `assertz/1`, `retract/1`
|
||||
- [ ] `findall/3`, `bagof/3`, `setof/3`
|
||||
- [ ] `copy_term/2`, `functor/3`, `arg/3`, `=../2`
|
||||
- [ ] String/atom predicates
|
||||
|
||||
### Phase 5 — Hyperscript integration
|
||||
- [ ] `prolog-query` primitive callable from SX/Hyperscript
|
||||
- [ ] Hyperscript DSL: `when allowed(user, :edit) then …`
|
||||
- [ ] Integration suite
|
||||
|
||||
### Phase 6 — ISO conformance
|
||||
- [ ] Vendor Hirst's conformance tests
|
||||
- [ ] Drive scoreboard to 200+
|
||||
|
||||
### Phase 7 — compiler (later, optional)
|
||||
- [ ] Compile clauses to SX continuations for speed
|
||||
- [ ] Keep interpreter as the reference
|
||||
|
||||
## Progress log
|
||||
|
||||
_Newest first. Agent appends on every commit._
|
||||
|
||||
- _(awaiting phase 1)_
|
||||
|
||||
## Blockers
|
||||
|
||||
_Shared-file issues that need someone else to fix. Minimal repro only._
|
||||
|
||||
- _(none yet)_
|
||||
101
plans/restore-all.sh
Executable file
101
plans/restore-all.sh
Executable file
@@ -0,0 +1,101 @@
|
||||
#!/usr/bin/env bash
|
||||
# restore-all.sh — snapshot recovery state for every language loop.
|
||||
#
|
||||
# Shows: per-language branch, recent commits, test/scoreboard status, plan progress.
|
||||
# Points at the briefing file for each language. To respawn a loop, paste the
|
||||
# briefing into Claude via the Agent tool with run_in_background=true and
|
||||
# isolation=worktree.
|
||||
#
|
||||
# Usage:
|
||||
# bash plans/restore-all.sh # status for all languages
|
||||
# bash plans/restore-all.sh <lang> # one language (js|hs|lua|prolog|forth|erlang|haskell)
|
||||
# bash plans/restore-all.sh --print # also cat each briefing
|
||||
#
|
||||
set -uo pipefail
|
||||
|
||||
cd "$(dirname "$0")/.."
|
||||
|
||||
LANGS=(js hs lua prolog forth erlang haskell)
|
||||
FILTER="${1:-}"
|
||||
PRINT=""
|
||||
if [ "$FILTER" = "--print" ]; then PRINT="yes"; FILTER=""; fi
|
||||
|
||||
snap_one() {
|
||||
local lang="$1"
|
||||
local plan
|
||||
local dir
|
||||
local scoreboard
|
||||
local tests_cmd
|
||||
local briefing
|
||||
|
||||
case "$lang" in
|
||||
js) plan="plans/js-on-sx.md"; dir="lib/js"; scoreboard="lib/js/test262-scoreboard.md"; briefing="plans/agent-briefings/loop.md"; tests_cmd="bash lib/js/test.sh";;
|
||||
hs) plan="plans/hs-conformance-to-100.md"; dir="lib/hyperscript"; scoreboard="plans/hs-conformance-scoreboard.md"; briefing="plans/agent-briefings/hs-loop.md"; tests_cmd="bash lib/hyperscript/test.sh";;
|
||||
lua) plan="plans/lua-on-sx.md"; dir="lib/lua"; scoreboard="lib/lua/scoreboard.md"; briefing="plans/agent-briefings/lua-loop.md"; tests_cmd="bash lib/lua/conformance.sh";;
|
||||
prolog) plan="plans/prolog-on-sx.md"; dir="lib/prolog"; scoreboard="lib/prolog/scoreboard.md"; briefing="plans/agent-briefings/prolog-loop.md"; tests_cmd="bash lib/prolog/conformance.sh";;
|
||||
forth) plan="plans/forth-on-sx.md"; dir="lib/forth"; scoreboard="lib/forth/scoreboard.md"; briefing="plans/agent-briefings/forth-loop.md"; tests_cmd="bash lib/forth/conformance.sh";;
|
||||
erlang) plan="plans/erlang-on-sx.md"; dir="lib/erlang"; scoreboard="lib/erlang/scoreboard.md"; briefing="plans/agent-briefings/erlang-loop.md"; tests_cmd="bash lib/erlang/conformance.sh";;
|
||||
haskell) plan="plans/haskell-on-sx.md"; dir="lib/haskell"; scoreboard="lib/haskell/scoreboard.md"; briefing="plans/agent-briefings/haskell-loop.md"; tests_cmd="bash lib/haskell/conformance.sh";;
|
||||
*) echo "unknown lang: $lang"; return 1;;
|
||||
esac
|
||||
|
||||
echo "=== $lang ==="
|
||||
if [ -f "$plan" ]; then
|
||||
echo "plan: $plan"
|
||||
else
|
||||
echo "plan: (missing)"
|
||||
fi
|
||||
if [ -f "$briefing" ]; then
|
||||
echo "briefing: $briefing"
|
||||
else
|
||||
echo "briefing: (missing — cannot respawn)"
|
||||
fi
|
||||
if [ -d "$dir" ]; then
|
||||
echo "dir: $dir ($(find "$dir" -type f 2>/dev/null | wc -l) files)"
|
||||
else
|
||||
echo "dir: $dir (does not exist yet)"
|
||||
fi
|
||||
if [ -f "$scoreboard" ]; then
|
||||
echo "scoreboard: $scoreboard"
|
||||
head -3 "$scoreboard" | sed 's/^/ /'
|
||||
else
|
||||
echo "scoreboard: (not yet generated)"
|
||||
fi
|
||||
echo "recent commits (vs main):"
|
||||
git log --oneline "main..HEAD" -- "$dir" "$plan" 2>/dev/null | head -5 | sed 's/^/ /' || echo " (none)"
|
||||
echo
|
||||
}
|
||||
|
||||
echo "=== environment ==="
|
||||
echo "branch: $(git rev-parse --abbrev-ref HEAD)"
|
||||
echo "HEAD: $(git log -1 --oneline)"
|
||||
if [ -x hosts/ocaml/_build/default/bin/sx_server.exe ]; then
|
||||
echo "sx_server: present"
|
||||
else
|
||||
echo "sx_server: MISSING — build with ./scripts/sx-build-all.sh before spawning any agent"
|
||||
fi
|
||||
echo "worktrees: $(git worktree list | wc -l)"
|
||||
echo
|
||||
|
||||
if [ -n "$FILTER" ]; then
|
||||
snap_one "$FILTER"
|
||||
else
|
||||
for l in "${LANGS[@]}"; do snap_one "$l"; done
|
||||
fi
|
||||
|
||||
echo "=== to spawn a loop ==="
|
||||
echo "Paste the target briefing into Claude via the Agent tool with"
|
||||
echo " run_in_background: true"
|
||||
echo " isolation: worktree"
|
||||
echo "The briefing is self-contained; the agent reads the plan's Progress log"
|
||||
echo "and picks up from wherever the last commit left off."
|
||||
|
||||
if [ "$PRINT" = "yes" ]; then
|
||||
echo
|
||||
echo "=== all briefings ==="
|
||||
for f in plans/agent-briefings/*.md; do
|
||||
echo
|
||||
echo "---- $f ----"
|
||||
cat "$f"
|
||||
done
|
||||
fi
|
||||
Reference in New Issue
Block a user