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>
5.5 KiB
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.14natively;(+ 1.5 2.5) → 4.0;strformats with%g(compact, no trailing zeros).floor/ceil/round/truncateall exist inspec/primitives.sx. - Regex —
regexp-match,regexp-match-all,regexp-replace,regexp-replace-all,regexp-splitare registered OCaml primitives usingRe.Pcre(hosts/ocaml/lib/sx_primitives.ml). call/ccmulti-shot — works.set!on closed-over vars works. Fibers are implementable as a pure SX library.performuser-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:
; 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:
(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
- Phase 1 — immediate Tcl wins, zero risk, proves the approach
- Phase 2 (
lib/fiber.sx) — the interesting SX work, benefits all hosted languages - Phase 3 (OCaml primitives) — quick practical completions
- 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 requireof binary loadables- Full
clock formatlocale support - Tk / GUI
- Threads (mapped to coroutines only, as planned)
- Full POSIX file I/O (seek/tell/async) — stubs are fine