Hyperscript compiler/runtime:
- query target support in set/fire/put commands
- hs-set-prolog-hook! / hs-prolog-hook / hs-prolog in runtime
- runtime log-capture cleanup
Scripts: sx-loops-up/down, sx-hs-e-up/down, sx-primitives-down
Plans: datalog, elixir, elm, go, koka, minikanren, ocaml, hs-bucket-f,
designs (breakpoint, null-safety, step-limit, tell, cookies, eval,
plugin-system)
lib/prolog/hs-bridge.sx: initial hook-based bridge draft
lib/common-lisp/tests/runtime.sx: CL runtime tests
WASM: regenerate sx_browser.bc.js from updated hs sources
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
146 lines
7.5 KiB
Markdown
146 lines
7.5 KiB
Markdown
# Go-on-SX: Go on the CEK/VM
|
|
|
|
Compile Go source to SX AST; the existing CEK evaluator runs it. The unique angle: Go's
|
|
goroutines and channels map cleanly onto SX's IO suspension machinery (`perform`/`cek-resume`)
|
|
— a goroutine is a `cek-step-loop` running in a cooperative scheduler, a channel send/receive
|
|
is a `perform` that suspends until the other end is ready.
|
|
|
|
End-state goal: **core Go programs running**, including goroutines, channels, defer/panic/recover,
|
|
interfaces, and structs. Not a full Go compiler — no generics, no CGo, no full stdlib — but
|
|
a faithful runtime for idiomatic Go concurrent programs.
|
|
|
|
## Ground rules
|
|
|
|
- **Scope:** only touch `lib/go/**` and `plans/go-on-sx.md`. Do **not** edit `spec/`,
|
|
`hosts/`, `shared/`, or other `lib/<lang>/`.
|
|
- **Shared-file issues** go under "Blockers" below with a minimal repro; do not fix here.
|
|
- **SX files:** use `sx-tree` MCP tools only.
|
|
- **Architecture:** Go source → Go AST → SX AST. No standalone Go evaluator.
|
|
- **Concurrency model:** cooperative, not preemptive. Goroutines yield at channel ops and
|
|
`time.Sleep`. A round-robin scheduler in SX drives them.
|
|
- **Commits:** one feature per commit. Keep `## Progress log` updated and tick boxes.
|
|
|
|
## Architecture sketch
|
|
|
|
```
|
|
Go source text
|
|
│
|
|
▼
|
|
lib/go/tokenizer.sx — Go tokens: keywords, idents, string/rune/number literals,
|
|
│ operators, semicolon insertion rules
|
|
▼
|
|
lib/go/parser.sx — Go AST: package, import, var, const, type, func, struct,
|
|
│ interface, goroutine, channel ops, defer, select, for range
|
|
▼
|
|
lib/go/transpile.sx — Go AST → SX AST
|
|
│
|
|
▼
|
|
lib/go/runtime.sx — goroutine scheduler, channel primitives, defer stack,
|
|
│ panic/recover, interface dispatch, slice/map ops
|
|
▼
|
|
CEK / VM
|
|
```
|
|
|
|
Key semantic mappings:
|
|
- `go fn()` → spawn new coroutine (SX coroutine primitive, Phase 4 of primitives)
|
|
- `ch <- v` (send) → `perform` that suspends until receiver ready; scheduler picks next goroutine
|
|
- `v := <-ch` (receive) → `perform` that suspends until sender ready
|
|
- `select { case ... }` → scheduler checks all channel readiness, picks first ready
|
|
- `defer fn()` → push onto a per-goroutine defer stack; run on return/panic
|
|
- `panic(v)` → `raise` the value; `recover()` catches it in deferred function
|
|
- `interface{}` → any SX value (duck typed)
|
|
- `struct { ... }` → SX hash table with field names as keys
|
|
- `slice` → SX vector with length + capacity metadata
|
|
- `map[K]V` → SX mutable hash table (Phase 10 of primitives)
|
|
|
|
## Roadmap
|
|
|
|
### Phase 1 — tokenizer + parser
|
|
- [ ] Tokenizer: keywords (`package`, `import`, `func`, `var`, `const`, `type`, `struct`,
|
|
`interface`, `go`, `chan`, `select`, `defer`, `return`, `if`, `else`, `for`, `range`,
|
|
`switch`, `case`, `default`, `break`, `continue`, `goto`, `fallthrough`, `map`,
|
|
`make`, `new`, `nil`, `true`, `false`), automatic semicolon insertion, string literals
|
|
(interpreted + raw `` `...` ``), rune literals `'a'`, number literals (int, float, hex,
|
|
octal, binary, complex), operators, slices `[:]`
|
|
- [ ] Parser: package clause, imports, top-level `func`/`var`/`const`/`type`; function
|
|
bodies: short variable decl `:=`, assignments, `if`/`else`, `for`/`range`, `switch`,
|
|
`return`, struct literals, slice literals, map literals, composite literals, type
|
|
assertions `v.(T)`, method calls `v.Method(args)`, goroutine `go`, channel ops
|
|
`<-ch`, `ch <- v`, `defer`, `select`
|
|
- [ ] Tests in `lib/go/tests/parse.sx`
|
|
|
|
### Phase 2 — transpile: basic Go (no goroutines)
|
|
- [ ] `go-eval-ast` entry
|
|
- [ ] Arithmetic, string ops, comparison, boolean
|
|
- [ ] Variables, short decl, assignment, multiple assignment
|
|
- [ ] `if`/`else if`/`else`
|
|
- [ ] `for` (C-style), `for range` over slice/map/string
|
|
- [ ] Functions: named + anonymous, multiple return values (SX multiple values, Phase 8)
|
|
- [ ] Structs → SX hash tables; field access `.field`; struct literals `T{f: v}`
|
|
- [ ] Slices → SX vectors; `len`, `cap`, `append`, `copy`, slice expressions `s[a:b]`
|
|
- [ ] Maps → SX hash tables; `make(map[K]V)`, `m[k]`, `m[k] = v`, `delete(m, k)`,
|
|
comma-ok `v, ok := m[k]`
|
|
- [ ] Pointers — modelled as single-element mutable vectors; `&x` creates wrapper, `*p` dereferences
|
|
- [ ] `fmt.Println`/`fmt.Printf`/`fmt.Sprintf` → SX IO perform (print)
|
|
- [ ] 40+ eval tests in `lib/go/tests/eval.sx`
|
|
|
|
### Phase 3 — defer / panic / recover
|
|
- [ ] Defer stack per function frame — SX list of thunks, run LIFO on return
|
|
- [ ] `defer` statement pushes thunk; transpiler wraps function body in try/finally equivalent
|
|
- [ ] `panic(v)` → `raise` with Go panic wrapper
|
|
- [ ] `recover()` → catches panic value inside a deferred function; returns nil otherwise
|
|
- [ ] Panic propagation across call stack until recovered or fatal
|
|
- [ ] Tests: defer ordering, panic/recover, panic in goroutine without recover
|
|
|
|
### Phase 4 — goroutines + channels
|
|
- [ ] Coroutine-based goroutine type using SX coroutine primitive (Phase 4 of primitives)
|
|
- [ ] Round-robin scheduler in `lib/go/runtime.sx`: maintains run queue, steps each
|
|
goroutine one turn at a time, suspends at channel ops
|
|
- [ ] Unbuffered channels: `make(chan T)` → rendezvous point; send suspends until receive
|
|
and vice versa. Implemented as a pair of waiting queues + `cek-resume`.
|
|
- [ ] Buffered channels: `make(chan T, n)` → circular buffer; send only blocks when full,
|
|
receive only blocks when empty
|
|
- [ ] `close(ch)` — mark channel closed; receivers drain then get zero value + `false`
|
|
- [ ] `select` — scheduler inspects all cases, picks a ready one (random if multiple),
|
|
blocks if none ready until at least one becomes ready
|
|
- [ ] `go fn(args)` — spawns new goroutine on run queue
|
|
- [ ] `time.Sleep(d)` — yields current goroutine, re-queues after d milliseconds
|
|
(simulated with IO perform timer)
|
|
- [ ] Tests: ping-pong, fan-out, fan-in, select with default, range over channel
|
|
|
|
### Phase 5 — interfaces
|
|
- [ ] Interface type → SX dict `{:type "T" :methods {...}}` dispatch table
|
|
- [ ] `interface{}` / `any` → any SX value (already implicit)
|
|
- [ ] Type assertion `v.(T)` → check `:type` field, panic if mismatch
|
|
- [ ] Type switch `switch v.(type) { case T: ... }` → dispatches on `:type`
|
|
- [ ] Method sets — structs implement interfaces implicitly if they have the right methods
|
|
- [ ] Value vs pointer receivers — pointer receiver gets the mutable vector wrapper
|
|
- [ ] Built-in interfaces: `error` (`Error() string`), `Stringer` (`String() string`)
|
|
- [ ] Tests: interface satisfaction, type assertion, type switch, error interface
|
|
|
|
### Phase 6 — standard library subset
|
|
- [ ] `fmt` — `Println`, `Printf`, `Sprintf`, `Fprintf`, `Errorf`, `Stringer` dispatch
|
|
- [ ] `strings` — `Contains`, `HasPrefix`, `HasSuffix`, `Split`, `Join`, `TrimSpace`,
|
|
`ToUpper`, `ToLower`, `Replace`, `Index`, `Count`, `Repeat`
|
|
- [ ] `strconv` — `Itoa`, `Atoi`, `FormatFloat`, `ParseFloat`, `ParseInt`, `FormatInt`
|
|
- [ ] `math` — full surface via SX math primitives (Phase 15)
|
|
- [ ] `sort` — `sort.Slice`, `sort.Ints`, `sort.Strings`
|
|
- [ ] `errors` — `errors.New`, `errors.Is`, `errors.As`
|
|
- [ ] `sync` — `sync.Mutex` (cooperative — just a boolean flag + goroutine queue),
|
|
`sync.WaitGroup`, `sync.Once`
|
|
- [ ] `io` — `io.Reader`/`io.Writer` interfaces; `io.ReadAll`; `strings.NewReader`
|
|
|
|
### Phase 7 — full conformance target
|
|
- [ ] Vendor a Go test suite or hand-build 100+ program tests in `lib/go/tests/programs/`
|
|
- [ ] Drive scoreboard
|
|
|
|
## Blockers
|
|
|
|
_(none yet)_
|
|
|
|
## Progress log
|
|
|
|
_Newest first._
|
|
|
|
_(awaiting phase 1)_
|