plans: tcl-sx-completion — phased plan for remaining Tcl limitations
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 17s
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 17s
Phase 1: zero-cost wins (float/regex/apply/arrays, no SX changes) Phase 2: lib/fiber.sx (pure SX fibers via call/cc + set!) Phase 3: small OCaml additions (file-read, clock-seconds, etc.) Phase 4: env-as-value (optional architectural cleanup) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
146
plans/tcl-sx-completion.md
Normal file
146
plans/tcl-sx-completion.md
Normal file
@@ -0,0 +1,146 @@
|
||||
# Tcl-on-SX completion plan — SX capabilities first
|
||||
|
||||
Tcl phases 1–6 are complete (329/329 tests). This plan covers the remaining
|
||||
limitations, ordered by the SX work needed to enable them.
|
||||
|
||||
## Key audit findings
|
||||
|
||||
Several apparent gaps are already solved in SX:
|
||||
|
||||
- **Floats** — SX parses `3.14` natively; `(+ 1.5 2.5) → 4.0`; `str` formats
|
||||
with `%g` (compact, no trailing zeros). `floor`/`ceil`/`round`/`truncate`
|
||||
all exist in `spec/primitives.sx`.
|
||||
- **Regex** — `regexp-match`, `regexp-match-all`, `regexp-replace`,
|
||||
`regexp-replace-all`, `regexp-split` are registered OCaml primitives using
|
||||
`Re.Pcre` (`hosts/ocaml/lib/sx_primitives.ml`).
|
||||
- **`call/cc` multi-shot** — works. `set!` on closed-over vars works. Fibers
|
||||
are implementable as a pure SX library.
|
||||
- **`perform` user-accessible** — `(perform :foo 42)` from user code suspends
|
||||
the evaluator and emits an IO request. The algebraic effects model is
|
||||
already half-built.
|
||||
- **No `file-read`/`clock-seconds`** — not yet registered as OCaml primitives.
|
||||
Only string ports exist. Would need small OCaml additions.
|
||||
- **No `env-as-value`** — environments are internal OCaml values, not
|
||||
inspectable from SX user code.
|
||||
|
||||
---
|
||||
|
||||
## Phase 1 — Zero-cost wins (no SX changes, only `lib/tcl/`)
|
||||
|
||||
Everything here is pure Tcl implementation work.
|
||||
|
||||
| Work | Effort | Unlocks in Tcl |
|
||||
|---|---|---|
|
||||
| Float in `expr` — detect `.` in number tokens, route through float ops instead of `parse-int` | half day | `expr {3.14 * 2}`, `expr {sqrt(2.0)}`, float comparisons |
|
||||
| `regexp pattern str` and `regsub pattern str repl` wrapping existing SX primitives | few hours | pattern matching, text processing |
|
||||
| `apply {args body} ?arg…?` — anonymous proc call | 1 hour | higher-order functions, `lmap` idiom |
|
||||
| `array get/set/names/size/exists/unset` commands | half day | array variables (tokenizer already parses `$arr(key)`) |
|
||||
|
||||
**Total: ~2 days. Zero SX changes.**
|
||||
|
||||
---
|
||||
|
||||
## Phase 2 — `lib/fiber.sx` (pure SX library, no OCaml)
|
||||
|
||||
`call/cc` is multi-shot and `set!` on closed-over vars both work. Fibers are
|
||||
implementable as a pure SX library using symmetric continuation swapping:
|
||||
|
||||
```scheme
|
||||
; lib/fiber.sx — canonical fiber primitive for all hosted languages
|
||||
(define make-fiber
|
||||
(fn (thunk)
|
||||
(define slot-k nil)
|
||||
(define slot-caller nil)
|
||||
(define slot-done false)
|
||||
(fn (resume-val)
|
||||
(call/cc (fn (caller-k)
|
||||
(set! slot-caller caller-k)
|
||||
(if (nil? slot-k)
|
||||
(begin (thunk resume-val) (set! slot-done true) (caller-k nil))
|
||||
(slot-k resume-val)))))))
|
||||
|
||||
(define fiber-yield
|
||||
(fn (val)
|
||||
(call/cc (fn (k)
|
||||
(set! slot-k k)
|
||||
(slot-caller val)))))
|
||||
```
|
||||
|
||||
Each coroutine becomes a fiber. `yield` swaps to the caller; calling the
|
||||
coroutine name swaps back. True suspension, not eager pre-execution.
|
||||
|
||||
**Broader value:** Ruby fibers, Python generators, Lua coroutines, async event
|
||||
loops, cooperative schedulers all sit on top of the same library.
|
||||
|
||||
**Alternatively:** `perform` is user-accessible. A Tcl scheduler living outside
|
||||
the SX evaluator (the OCaml host or an SX event loop) could catch
|
||||
`(perform :fiber-yield val)` and dispatch it — the algebraic effects model,
|
||||
already half-built.
|
||||
|
||||
**Total: 2–3 days. Produces `lib/fiber.sx` as a lasting SX contribution.**
|
||||
Tcl coroutines then rewrite using `make-fiber` for true suspension.
|
||||
|
||||
---
|
||||
|
||||
## Phase 3 — Small OCaml additions (`sx_primitives.ml`)
|
||||
|
||||
Each is ~10–20 lines of OCaml. All are useful across the whole platform, not
|
||||
just Tcl.
|
||||
|
||||
| Primitive | OCaml effort | Unlocks |
|
||||
|---|---|---|
|
||||
| `(file-read path)` → string | tiny | Tcl `open`/`read`, SX scripts reading files |
|
||||
| `(file-write path str)` → nil | tiny | Tcl `open`/`puts` to files |
|
||||
| `(file-exists? path)` → bool | tiny | Tcl `file exists` |
|
||||
| `(file-glob pattern)` → list | small | Tcl `glob` |
|
||||
| `(clock-seconds)` → int | tiny | Tcl `clock seconds` |
|
||||
| `(clock-format n fmt)` → string | small (wraps `strftime`) | Tcl `clock format` |
|
||||
|
||||
**Total: 1 day. One focused afternoon of OCaml.**
|
||||
|
||||
---
|
||||
|
||||
## Phase 4 — Optional: env-as-value (architectural)
|
||||
|
||||
`uplevel`/`upvar` required an explicit frame stack because SX environments
|
||||
aren't inspectable from user code. Adding:
|
||||
|
||||
```scheme
|
||||
(current-env) ; → env value
|
||||
(eval-in-env env expr) ; → result
|
||||
(env-lookup env key) ; → value or nil
|
||||
(env-extend env key val) ; → new env (non-mutating)
|
||||
```
|
||||
|
||||
...would let `uplevel N` be literally "look up env N levels up, eval in it."
|
||||
The Tcl frame stack (hundreds of lines) collapses to ~10 lines.
|
||||
|
||||
Also benefits: metacircular evaluators, REPL tooling, live debugging (inspect
|
||||
any scope), the sx_docs server's eval endpoint.
|
||||
|
||||
More invasive — touches `sx_types.ml` and `sx_server.ml` — but a meaningful
|
||||
architectural improvement worth doing when the moment is right.
|
||||
|
||||
**Total: 2–3 days. High architectural value, not urgent.**
|
||||
|
||||
---
|
||||
|
||||
## Suggested order
|
||||
|
||||
1. **Phase 1** — immediate Tcl wins, zero risk, proves the approach
|
||||
2. **Phase 2** (`lib/fiber.sx`) — the interesting SX work, benefits all hosted languages
|
||||
3. **Phase 3** (OCaml primitives) — quick practical completions
|
||||
4. **Phase 4** — architectural cleanup when it's worth the invasiveness
|
||||
|
||||
Phases 1+2+3 ≈ one focused week. Tcl is genuinely complete, and `lib/fiber.sx`
|
||||
becomes a lasting SX contribution used by every future hosted language.
|
||||
|
||||
---
|
||||
|
||||
## What stays out of scope
|
||||
|
||||
- `package require` of binary loadables
|
||||
- Full `clock format` locale support
|
||||
- Tk / GUI
|
||||
- Threads (mapped to coroutines only, as planned)
|
||||
- Full POSIX file I/O (seek/tell/async) — stubs are fine
|
||||
Reference in New Issue
Block a user