- go-on-sx.md: rewrite of 2026-04-26 draft to integrate lib/guest framework. Adds Phase 3 (independent bidirectional type checker — first static-typed guest), Phase 10 (extraction enabler), chisel discipline, conformance scoreboard model. Phases 1-2 now consume lib/guest/core lex+pratt+ast. - lib-guest-scheduler.md: NEW. Extraction plan for the fork/yield/block/ resume scheduler shared by Erlang (addressed processes + mailboxes) and Go (anonymous channels + goroutines). Two-language rule blocks extraction until both consumers independently work; rejected-extraction is a valid outcome. - lib-guest-static-types-bidirectional.md: NEW. Sister to lib/guest/hm.sx. Bidirectional checker kit (synth/check judgments, pluggable subtype + unify) for the languages HM doesn't fit — Go, Rust, TS, Swift, Kotlin, Scala 3, Hack. First consumer: Go-on-SX. Second TBD; recommendation TypeScript. The three plans cross-reference each other. Go-on-SX implements scheduler + checker independently of the kits; extraction is its own workstream once two consumers exist.
408 lines
20 KiB
Markdown
408 lines
20 KiB
Markdown
# Go-on-SX — Go as an SX guest language
|
|
|
|
Port Go to SX as the **first static-typed, bidirectional-checked guest** in
|
|
the rose-ash language family. Goal isn't a production Go compiler; it's to
|
|
prove the substrate from a paradigm angle the existing eleven guests don't
|
|
cover, and to chisel out the lib/guest kits that statically-typed guests N+1
|
|
and N+2 will need.
|
|
|
|
Reference:
|
|
- `plans/lib-guest.md` — parent, chiselling discipline, two-language rule.
|
|
- `plans/lib-guest-scheduler.md` — sister kit; Go's scheduler pairs with
|
|
Erlang's. Extraction gated on this loop reaching Phase 5.
|
|
- `plans/lib-guest-static-types-bidirectional.md` — sister kit; Go's
|
|
checker pairs with a TBD second consumer. Extraction gated on this loop
|
|
reaching Phase 3.
|
|
- `plans/erlang-on-sx.md` — reference implementation for paradigm-port:
|
|
process model, BIF registry, hot reload, VM bytecode opcodes.
|
|
|
|
**Branch:** `loops/go` (loop-style workstream once kicked off). SX files via
|
|
`sx-tree` MCP only.
|
|
|
|
## Thesis — why Go
|
|
|
|
Eleven guests already live in `lib/`: apl, common-lisp, datalog, erlang,
|
|
forth, haskell, hyperscript, js, kernel, lua, minikanren, ocaml, prolog,
|
|
ruby, scheme, smalltalk, tcl. Every one is either **dynamically typed**
|
|
(most) or **HM-inferred** (haskell, ocaml). None exercise:
|
|
|
|
1. **Bidirectional static type checking** — annotation-driven, locally-
|
|
inferred, the dominant paradigm of modern statically-typed languages.
|
|
2. **Anonymous-channel concurrency** — Go's `chan` and `select`. Erlang has
|
|
addressed processes + mailboxes; Go has anonymous values + structural
|
|
pairing. Two different vocabularies for the same underlying scheduler
|
|
machinery.
|
|
3. **Structural interfaces** — `io.Reader` is "anything with this method
|
|
signature", not a declared subtype relationship. Different from Haskell
|
|
typeclasses (nominal), different from Lua duck typing (no declaration).
|
|
|
|
These three together make Go an unusually high-value port for proving SX.
|
|
If SX can host Go cleanly, it can host the next decade of mainstream
|
|
statically-typed languages (Rust, TS, Swift, Kotlin, Scala 3, Hack) because
|
|
they share these three properties.
|
|
|
|
Like Erlang-on-SX validated the actor model on the substrate, Go-on-SX
|
|
validates the goroutine model + bidirectional types.
|
|
|
|
## Non-goals (deliberate)
|
|
|
|
Out of scope. Reject feature requests for these without further consideration:
|
|
|
|
- **`unsafe` package.** Memory mucking. Skip entirely.
|
|
- **CGo.** C interop. Out of scope at every level.
|
|
- **Full `reflect`.** Provide enough for `fmt.Println` to render values;
|
|
reject the rest.
|
|
- **Build tags, modules, vendoring.** Treat source as monolithic. One
|
|
package per file, no real import resolution.
|
|
- **Production performance.** Conformance tests pass; benchmarks don't.
|
|
- **Garbage collection tuning.** SX's GC is what you get.
|
|
- **Race detector, escape analysis, inlining.** Out of scope.
|
|
- **`os`, `net/http`, full stdlib.** Provide a deliberately small slice
|
|
(Phase 8 below).
|
|
|
|
## Architecture sketch
|
|
|
|
```
|
|
Go source text
|
|
│
|
|
▼
|
|
lib/go/lex.sx — tokens; ASI; literals; operators
|
|
│ (consumes lib/guest/core/lex.sx)
|
|
▼
|
|
lib/go/parse.sx — AST: package/import/var/const/type/func/struct/
|
|
│ interface; expressions; statements
|
|
│ (consumes lib/guest/core/pratt.sx + ast.sx)
|
|
▼
|
|
lib/go/types.sx — bidirectional type checker. Synth + check judgments;
|
|
│ structural interface satisfaction; pluggable subtype
|
|
│ (INDEPENDENT — no lib/guest/static-types-bidirectional
|
|
│ yet; this loop builds the first consumer)
|
|
▼
|
|
lib/go/eval.sx — tree-walk evaluator on CEK. Variables as mutable cells;
|
|
│ slices = (length, capacity, backing-vector); maps =
|
|
│ SX dict; defer stack per frame.
|
|
▼
|
|
lib/go/sched.sx — goroutine scheduler + channels + select
|
|
│ (INDEPENDENT — no lib/guest/scheduler yet; this loop
|
|
│ builds the first consumer)
|
|
▼
|
|
lib/go/std/ — minimal stdlib slice (fmt, strings, strconv, sync,
|
|
time, errors)
|
|
```
|
|
|
|
Semantic mappings (operational):
|
|
- `go fn(args)` → `task-spawn` on the local scheduler.
|
|
- `ch <- v` → `task-block` with predicate "receiver waiting on ch".
|
|
- `v := <-ch` → `task-block` with predicate "sender waiting on ch".
|
|
- `select { case ... }` → `task-block` with predicate "any case ready".
|
|
- `defer fn()` → push thunk onto per-frame defer stack; runs LIFO on
|
|
return or panic.
|
|
- `panic(v)` → raise SX exception; deferred fns run while unwinding.
|
|
- `recover()` → CEK exception capture inside a deferred fn.
|
|
- `interface{T}` → type-check matches structurally against T's method
|
|
set; at runtime, the value carries its concrete-type metadata.
|
|
- `struct{...}` → SX dict + type tag; methods are functions in the type's
|
|
method table.
|
|
- `*T` (pointer) → mutable cell (Common Lisp port did the same).
|
|
- `[]T` (slice) → triple (length, capacity, backing-vector).
|
|
- `map[K]V` → SX dict; iteration order spec-undefined (v1 = sorted for
|
|
determinism — programs that depend on indeterminism fail loudly, which
|
|
is a feature not a bug).
|
|
|
|
## Conformance scoreboard
|
|
|
|
Following `lib/erlang/scoreboard.json` precedent. Add
|
|
`lib/go/scoreboard.json` on first iteration; populate as suites land.
|
|
Suites planned:
|
|
|
|
| Suite | Tests target | What it covers |
|
|
|---|---|---|
|
|
| `lex` | 50+ | Keywords, operators, literals, ASI |
|
|
| `parse` | 80+ | All statement & expression shapes |
|
|
| `types` | 90+ | Synth, check, interface satisfaction, generics |
|
|
| `eval` | 100+ | Tree-walk over typed AST |
|
|
| `runtime` | 60+ | Goroutines, channels, select, close |
|
|
| `stdlib` | 40+ | fmt, strings, strconv, sync, time, errors |
|
|
| `e2e` | 10+ | Complete representative programs |
|
|
|
|
## Phasing — one feature per commit
|
|
|
|
Loop-style. Each phase: implement → test → commit → tick `[ ]` → append
|
|
Progress-log line → push `origin/loops/go`.
|
|
|
|
### Phase 1 — Tokenizer (`lib/go/lex.sx`) ⬜
|
|
- Consume `lib/guest/core/lex.sx`. Tag the chisel note `consumes-lex`.
|
|
- Keywords (25), operators + punctuation (47 distinct), identifiers,
|
|
literals (int / float / imaginary / rune / string with raw + interpreted
|
|
variants), comments.
|
|
- **Automatic semicolon insertion** — the one tricky bit. Newline becomes
|
|
`;` after identifier/literal/`)`/`]`/`}` per Go spec § Semicolons. Build
|
|
it into the tokenizer, not the parser.
|
|
- Tests: golden-token streams for every keyword/operator/literal kind +
|
|
ASI edge cases.
|
|
- **Acceptance:** lex/ suite at 50+ tests.
|
|
|
|
### Phase 2 — Parser (`lib/go/parse.sx`) ⬜
|
|
- Consume `lib/guest/core/pratt.sx` + `lib/guest/core/ast.sx`. Chisel notes
|
|
`consumes-pratt consumes-ast`.
|
|
- Grammar coverage:
|
|
- Declarations: `package`, `import`, `var`, `const`, `type`, `func`
|
|
- Types: basic, slice `[]T`, array `[N]T`, map `map[K]V`, chan `chan T`,
|
|
func `func(...)...`, struct, interface, pointer `*T`
|
|
- Expressions: literals, identifier, call, index `[]`, slice `[a:b]`,
|
|
type assertion `v.(T)`, operators
|
|
- Statements: `if`/`else`, `for` (C-style + range), `switch`, `select`,
|
|
`return`, `defer`, `go`, `break`/`continue`, assign, short-decl `:=`,
|
|
send `ch <- v`, recv `<-ch`
|
|
- Output: SX-shaped AST per `lib/guest/core/ast.sx` conventions.
|
|
- Tests: round-trip parse of hello world, fibonacci, FizzBuzz, goroutine
|
|
ping-pong, struct + method.
|
|
- **Acceptance:** parse/ suite at 80+ tests.
|
|
|
|
### Phase 3 — Bidirectional type checker, MVP (`lib/go/types.sx`) ⬜
|
|
- **Independent implementation.** Do NOT use lib/guest/static-types-
|
|
bidirectional/ — that kit doesn't exist yet and depends on this work
|
|
for its design. See `plans/lib-guest-static-types-bidirectional.md`.
|
|
- Synth + check judgments. Context as a value (per-block scope).
|
|
- Coverage MVP: declared-type variables, function signatures (params +
|
|
returns), call type-checking, simple composite types (slice, map, chan
|
|
element), interface satisfaction (structural match against method sets),
|
|
short variable declaration `:=` (synth from RHS).
|
|
- **Untyped constants.** `42` has type `untyped int` until contextualised;
|
|
this is the canonical pitfall (see Gotchas below).
|
|
- Defer: generics (Phase 7), full conversion rules.
|
|
- Tests: positive (type-correct programs check) + negative (mismatched
|
|
types fail with informative errors carrying AST paths).
|
|
- **Acceptance:** types/ suite at 60+ tests. Chisel note `shapes-static-
|
|
types-bidirectional` — append a paragraph to the sister plan's design
|
|
diary describing what synth/check shape emerged.
|
|
|
|
### Phase 4 — Tree-walk evaluator (`lib/go/eval.sx`) ⬜
|
|
- AST-walking interpreter over CEK. Each Go statement maps to one step
|
|
function (precedent: `step-sf-if` etc. in spec/evaluator.sx).
|
|
- Variables: mutable cells. Pointer semantics: `&x` returns the cell,
|
|
`*p` dereferences.
|
|
- Slices: triple (length, capacity, backing-vector). `append` honours
|
|
capacity-grow per spec.
|
|
- Maps: SX dict + key-type metadata.
|
|
- Structs: SX dict + type tag. Methods looked up via type's method table.
|
|
- Functions: closures over enclosing scope; multiple return values.
|
|
- Channels: stub (Phase 5 wires them).
|
|
- Tests: arithmetic, control flow, recursion, closures, slices, maps,
|
|
structs, methods, pointer semantics, multiple-return.
|
|
- **Acceptance:** eval/ suite at 80+ tests. No concurrency yet.
|
|
|
|
### Phase 5 — Goroutines + channels + select (`lib/go/sched.sx`) ⬜
|
|
- **Independent implementation.** Do NOT use lib/guest/scheduler/ — that
|
|
kit doesn't exist yet and depends on this work for its design. See
|
|
`plans/lib-guest-scheduler.md`.
|
|
- `go expr` — spawn a goroutine; returns nothing.
|
|
- `chan T` — `make(chan T)` creates an unbuffered channel; `make(chan T,n)`
|
|
creates a buffered channel (Phase 5b — defer buffer to a sub-phase).
|
|
- `<-ch` — receive (blocks until sender ready).
|
|
- `ch <- v` — send (blocks until receiver ready for unbuffered, or buffer
|
|
has room for buffered).
|
|
- `select { case ... }` — non-deterministic multiplexing; `default` makes
|
|
it non-blocking.
|
|
- `close(ch)` — closes channel. Receive on closed → zero value + ok=false.
|
|
- Tests: ping-pong, fan-out/fan-in, work queue, select with default,
|
|
select with timeout (via a `time.After`-like stub), close semantics,
|
|
range over channel.
|
|
- **Acceptance:** runtime/ suite at 40+ tests. Chisel note `shapes-
|
|
scheduler` — append a paragraph to the sister plan's design diary
|
|
describing what task-spawn/block/wake/yield shape emerged.
|
|
|
|
### Phase 5b — Buffered channels + select fairness ⬜
|
|
- Buffered: send blocks only when buffer full; recv only when empty.
|
|
- `select` random case ordering (spec mandates pseudo-random; v1 uses a
|
|
fixed seed for determinism with a `runtime`-package knob to randomise).
|
|
- Tests: buffer-full blocking, buffer-empty blocking, select fairness
|
|
over many iterations.
|
|
- **Acceptance:** runtime/ +20 tests.
|
|
|
|
### Phase 6 — `defer` + panic/recover ⬜
|
|
- Defer stack per function frame; runs LIFO on return (normal or panic).
|
|
- `panic(v)` unwinds frames running deferreds; `recover()` inside a
|
|
deferred fn captures the panic value and stops unwinding.
|
|
- Goroutine panic propagation: a panicking goroutine that doesn't recover
|
|
crashes the whole program (honour Go spec, or document divergence).
|
|
- Tests: defer order (LIFO), defer + named-return mutation, panic/recover,
|
|
panic across goroutines, defer in a loop (push per iter, run on fn
|
|
return — common bug).
|
|
- **Acceptance:** eval/ +20 tests.
|
|
|
|
### Phase 7 — Generics (Go 1.18+) ⬜
|
|
- Type parameters with constraints (type sets: `interface{ int | float64
|
|
}`, `comparable`, `any`).
|
|
- Type inference at call sites — basic; the full Go inference algorithm
|
|
is notoriously complex. Implement enough for common cases; document
|
|
limitations in a Blockers section below.
|
|
- Tests: generic function (`func Map[T, U any](xs []T, f func(T) U) []U`),
|
|
generic data structure (linked list), constrained type param.
|
|
- **Acceptance:** types/ +30 tests.
|
|
|
|
### Phase 8 — Minimal stdlib (`lib/go/std/`) ⬜
|
|
- Implement just what's needed for representative programs:
|
|
- `fmt` — `Println`, `Printf`, `Sprintf`, `Fprintf`, `Errorf`,
|
|
`Stringer` dispatch. Verbs: `%d %s %v %t %f %T %+v`.
|
|
- `strings` — `Contains`, `HasPrefix`, `HasSuffix`, `Split`, `Join`,
|
|
`TrimSpace`, `ToUpper`, `ToLower`, `Replace`, `Index`, `Count`,
|
|
`Repeat`, `NewReader`.
|
|
- `strconv` — `Itoa`, `Atoi`, `FormatFloat`, `ParseFloat`, `ParseInt`,
|
|
`FormatInt`.
|
|
- `errors` — `New`, `Is`, `As`, `Unwrap`.
|
|
- `sync` — `Mutex` (cooperative — flag + waiter queue), `WaitGroup`,
|
|
`Once`, `RWMutex`.
|
|
- `time` — `Now`, `Since`, `After` (channel-returning timer), `Sleep`,
|
|
`Duration`, `Time`.
|
|
- `io` — `Reader`/`Writer` interfaces; `ReadAll`; `Copy`.
|
|
- `sort` — `Slice`, `Ints`, `Strings`.
|
|
- Tests: round-trip Itoa/Atoi, fmt verb coverage, sync.WaitGroup with
|
|
goroutines, time.After in a select, sort.Slice with custom less fn.
|
|
- **Acceptance:** stdlib/ suite at 40+ tests.
|
|
|
|
### Phase 9 — End-to-end programs ⬜
|
|
- Complete programs from canonical sources (gopl.io, "concurrency
|
|
patterns" talk examples) running end-to-end:
|
|
- Concurrent prime sieve
|
|
- HTTP-ish ping-pong over stubbed transport
|
|
- Word frequency counter
|
|
- Pipeline (channel chain)
|
|
- Producer/consumer with sync.WaitGroup
|
|
- "Bounded parallelism" pattern (worker pool over a job channel)
|
|
- **Acceptance:** e2e/ suite at 10+ tests, all passing.
|
|
|
|
### Phase 10 — lib/guest extraction enabler ⬜
|
|
- Now that Go has lex+parse+types+eval+sched, sister plans are unblocked
|
|
on the Go side. This phase is **doc-only** in `loops/go`:
|
|
- Cross-reference `plans/lib-guest-scheduler.md` — mark its Phase 1
|
|
(Go scheduler independent) as complete from Go's side.
|
|
- Cross-reference `plans/lib-guest-static-types-bidirectional.md` —
|
|
mark its Phase 1 as complete from Go's side.
|
|
- Update the chiselling diary in each sister plan with the actual
|
|
Go-side surface that emerged.
|
|
- **Acceptance:** sister plans cross-referenced + diaries updated. No
|
|
new Go code.
|
|
|
|
### Phase 11 — VM bytecode opcodes (deferred, optional) ⬜
|
|
- Following Erlang-on-SX Phase 10 precedent: identify hot paths in the
|
|
tree-walk evaluator, define Go-specific bytecode opcodes, compile hot
|
|
fns through them. Substantial work; only justified if Go programs
|
|
exercise enough volume that performance starts mattering.
|
|
- **Acceptance:** TBD on demand.
|
|
|
|
## Ground rules (loop-style)
|
|
|
|
- **Scope:** only `lib/go/**` and this plan. Do not touch `spec/`,
|
|
`hosts/`, `shared/`, `lib/guest/**` (read-only consumer at this phase),
|
|
or other `lib/<lang>/`.
|
|
- **Consume `lib/guest/core/`** for lex/parse/ast/match/layout. Hand-
|
|
rolling defeats the chiselling goal.
|
|
- **Do NOT extract into `lib/guest/scheduler/` or `lib/guest/static-
|
|
types-bidirectional/` from this loop.** Those extractions are gated on
|
|
two consumers AND the discipline of writing each consumer
|
|
independently. Extraction is its own workstream after Go and the
|
|
second consumer both exist.
|
|
- **Substrate gaps** → Blockers entry with minimal repro. Don't fix the
|
|
substrate from this loop. Belongs to `sx-improvements.md`.
|
|
- **NEVER call `sx_build` without timeout awareness** — 600s watchdog.
|
|
- **SX files:** `sx-tree` MCP tools ONLY. `sx_validate` after every edit.
|
|
- **Worktree:** branch `loops/go`, push `origin/loops/go`. Never `main`,
|
|
never `architecture`.
|
|
- **Commit granularity:** one feature per commit. Short factual messages:
|
|
`go: parse short-decl + 6 tests [consumes-pratt]`. Chisel note at end
|
|
in brackets.
|
|
- **Plan file:** update Progress log + tick boxes every commit.
|
|
- **If blocked** for two iterations on the same issue, add to Blockers
|
|
and move on. Phases 1-4 are sequential; Phases 5-8 are largely
|
|
independent once 4 lands.
|
|
|
|
## Chisel discipline (per parent lib-guest plan)
|
|
|
|
Every commit ends its message with a chisel note in brackets:
|
|
|
|
- `[consumes-X]` — used `lib/guest/X` kit.
|
|
- `[shapes-scheduler]` / `[shapes-static-types-bidirectional]` — revealed
|
|
something about what the sister lib-guest kits should look like. Add a
|
|
paragraph to the relevant sister plan's design diary.
|
|
- `[proposes-Y]` — revealed a gap in another existing kit. Blockers entry
|
|
in the kit's plan.
|
|
- `[nothing]` — pure Go work that didn't touch substrate or lib/guest
|
|
story. Acceptable; if it shows up twice in a row, stop and reflect.
|
|
|
|
## Go-specific gotchas
|
|
|
|
- **ASI (automatic semicolon insertion).** Newline becomes `;` after
|
|
identifier/literal/`)`/`]`/`}`. Build into the tokenizer; the Go spec's
|
|
"Semicolons" section is unusually precise — follow it literally.
|
|
- **Untyped constants.** `42` has type `untyped int` until used in a
|
|
context that forces a type. The canonical example: `var x float64 = 42
|
|
/ 7` — must compute as `untyped int / untyped int = 6` then convert to
|
|
`float64 = 6.0`. Wrong: float-coercing eagerly gives 6.0 prematurely.
|
|
Wrong: integer-truncating after coercion gives `5.something`. Test it.
|
|
- **Methods vs functions.** `func (r Receiver) Method()` is a method
|
|
bound to a type; `func Function(r Receiver)` is just a function.
|
|
Methods on pointer-receivers vs value-receivers have asymmetric
|
|
satisfaction in interfaces — pointer-receiver methods are NOT in the
|
|
value's method set for interface satisfaction.
|
|
- **Interface satisfaction is structural and silent.** Type satisfies an
|
|
interface if its method set contains all the interface's methods.
|
|
Lazy check: at every point a value flows into an interface-typed slot.
|
|
- **Channels are first-class values.** Pass them, store them, send them
|
|
through other channels. Each channel has identity.
|
|
- **`select` with `default`** = non-blocking. Without `default`, blocks
|
|
until a case is ready.
|
|
- **`nil` is typed.** `var x *int` makes x a `(*int)(nil)`. Comparison
|
|
`x == nil` works on typed nil; but `var i interface{} = (*int)(nil); i
|
|
== nil` is `false` — i holds a typed-nil-of-type-`*int`, not untyped
|
|
nil. The classic Go footgun. Test it.
|
|
- **Goroutine panic propagation.** A panicking goroutine that doesn't
|
|
recover crashes the whole program. Implement faithfully or document
|
|
divergence.
|
|
- **`defer` in a loop.** Each iteration pushes; they all run on function
|
|
return. Common bug; tests should cover.
|
|
- **Iteration order of maps.** Spec: unspecified. v1 = sorted by SX-
|
|
canonical key order for determinism; document that programs depending
|
|
on iteration order are not Go-conformant. Add a `runtime`-package knob
|
|
to enable randomisation later.
|
|
|
|
## Style
|
|
|
|
- No comments in `.sx` unless non-obvious. Cite Go spec sections inline
|
|
for non-obvious decisions (Go's spec is rigorous; citations work).
|
|
- No new planning docs — update this plan inline.
|
|
- One feature per iteration. Commit. Log. Push. Next.
|
|
|
|
## Open questions
|
|
|
|
1. **Module/import model.** Go has packages and import paths. Probably
|
|
model "package" as one or more `.sx` files in a directory, no real
|
|
import resolution against a remote module graph. Decide in Phase 2.
|
|
2. **Goroutine identity.** Spec says goroutines have no identity; the
|
|
scheduler does internally. Expose to user code? No (not Go). Expose
|
|
for debugging? Yes via a `runtime`-package stub.
|
|
3. **Error handling: panic-as-exception vs explicit error returns.** Go
|
|
strongly prefers explicit errors. Stdlib stubs follow that: `strconv.
|
|
Atoi("x")` returns `(0, err)`, not panic.
|
|
4. **Memory model.** Go has a happens-before model for atomics + channel
|
|
ops. SX runtime is single-threaded under the scheduler — every channel
|
|
op is a synchronization point automatically. Don't model relaxed
|
|
memory; document the simplification.
|
|
5. **Iteration order of maps.** Already addressed in Gotchas; flagged
|
|
here as a known divergence from spec.
|
|
|
|
## Blockers
|
|
|
|
_(none yet)_
|
|
|
|
## Progress log
|
|
|
|
_Newest first. Append one dated entry per commit._
|
|
|
|
- 2026-05-26 — Plan rewritten to integrate the lib/guest framework
|
|
(chiselling discipline, sister plans for scheduler + bidirectional
|
|
types, type-checker phase added, conformance scoreboard model adopted).
|
|
Original 2026-04-26 draft preserved in git history. Loop not yet
|
|
kicked off; Phase 1 (tokenizer) is the first iteration when this loop
|
|
spins up.
|