Commit Graph

20 Commits

Author SHA1 Message Date
63ad4563cb tcl: Phase 5d/5e/5f — file ops, clock locale+scan, socket -async
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 54s
Phase 5d (file metadata + ops):
- 11 SX primitives: file-size/mtime/stat/isfile?/isdir?/readable?/writable?/
  delete/mkdir/copy/rename — wrap Unix.stat/access/unlink/mkdir/rename
- Tcl `file` subcommands real (were stubs): isfile, isdir, readable,
  writable, size, mtime, atime, type, mkdir, copy, rename, delete
- file delete/copy/rename strip leading-`-` flags
- +10 idiom tests

Phase 5e (clock options + scan):
- clock-format extended to (t fmt tz), tz ∈ utc|local
- Added specifiers: %y, %I, %p, %w, %%
- New clock-scan SX primitive — format-driven parser + manual timegm
- Tcl clock format/scan accept -format, -timezone, -gmt 0|1
- +5 idiom tests

Phase 5f (socket -async):
- socket-connect-async SX primitive: Unix.set_nonblock + connect, catches
  EINPROGRESS; returns channel immediately
- channel-async-error: Unix.getsockopt_error
- Tcl `socket -async host port`; `fconfigure $sock -error`
- Connection completes on writable; canonical fileevent pattern works
- +3 idiom tests

Bug fix: tcl-call-proc was discarding :fileevents/:timers/:procs updates
made inside Tcl procs (only :commands forwarded). Now forwards full
result-interp as base, restoring caller's frame/stack/result/output/code.
This was masked until socket-async made fileevent-from-inside-proc the
natural pattern.

test.sh inner timeout bumped 1200s→2400s (post-merge JIT remains slow).

376/376 green.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-07 18:28:49 +00:00
c8b232d40e tcl: Phase 5c TCP sockets — client + server
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 1m4s
Three new SX primitives wrapping Unix socket APIs:
- socket-connect host port → "sockN" (TCP client)
- socket-server ?host? port → "sockN" listening socket (SO_REUSEADDR, backlog 8)
- socket-accept server-chan → {:channel :host :port}

Sockets reuse the channel_table from Phase 5, so existing channel-read/
write/close/select all work on them. Host arg supports localhost,
0.0.0.0, IPv4 literal, or gethostbyname lookup.

Tcl `socket` command:
- socket host port → TCP client
- socket -server cb port → listening socket; auto-registers a fileevent
  on the server channel that fires `_sock-do-accept SRV CB` per readable
  event. _sock-do-accept (internal) accepts the pending client and calls
  the user's callback as `cb client-chan host port`.

puts channel detection now also recognizes "sockN" prefix (was only
"fileN") and dispatches to channel-write.

+4 idiom tests: socket-server-fires-callback, socket-client-server-
roundtrip, socket-server-peer-host, socket-multiple-connections.
358/358 green.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-07 16:50:06 +00:00
64d36fa66e tcl: Phase 5b event loop — fileevent/after/vwait/update
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 1m3s
New SX primitive io-select-channels(read-list write-list timeout-ms) wrapping
Unix.select on the registered channel table. Returns {:readable :writable}.

Tcl event loop implemented purely in Tcl (no sx_server.ml changes):
- fileevent $chan readable|writable script (or "" to unregister)
- fileevent $chan event (1 arg) returns the registered script
- after ms script — schedule one-shot timer
- after ms (no script) — sleep, driving event loop in the meantime
- vwait varname — block until var is set/changed, handlers run between polls
- update — non-blocking event drain (poll-timeout=0)

State on interp: :fileevents (list of (chan event script)) and :timers
(sorted list of (expiry-ms script)).

tcl-event-step is the inner loop: expire timers, build fd lists from
:fileevents, call io-select-channels with computed timeout, run ready
handlers. vwait polls every 1000ms or until var changes.

Scoped to script mode by design — vwait from inside a server-handled
command does not interact with sx_server's stdin scheduler.

+5 idiom tests: after-vwait-timer, after-multiple-timers-update,
fileevent-readable-fires, fileevent-query-script,
after-cancel-via-vwait-timing. 354/354 green.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-07 12:47:31 +00:00
be820d0337 tcl: Phase 5 channel I/O — open/read/gets/puts/seek/tell/eof/fconfigure
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 2m0s
11 new SX primitives in sx_primitives.ml wrapping Unix.openfile/read/write/
lseek/set_nonblock: channel-open/close/read/read-line/write/flush/seek/tell/
eof?/blocking?/set-blocking!.

Tcl runtime now uses real channel ops:
- open ?-mode? returns "fileN" handle (modes r/w/a/r+/w+/a+)
- close/read/gets/puts/seek/tell/eof/flush wired through
- new fconfigure command supports -blocking 0|1
- puts dispatches to channel-write when first arg starts with "file"
- gets command registration fixed (was pointing to old stub)

eof-returns-1 coro test updated to match real Tcl semantics (eof flips
only after a read hits EOF).

Test runner timeout bumped 180s→1200s (post-merge JIT is slow).

+7 idiom tests covering write+read, gets-loop, seek/tell, eof-after-read,
append mode, seek-to-end, fconfigure-blocking. 349/349 green.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-07 09:28:44 +00:00
d21cde336a tcl: Phase 3 OCaml primitives — file-read/write/append/exists?/glob + clock-seconds/milliseconds/format in sx_primitives.ml + unix dep; tcl-cmd-clock/file wired up; 337/337 green
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 50s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 18:10:22 +00:00
f0f339709e tcl: replace eager coroutine pre-execution with true suspension via fibers
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 45s
Rewrote the coroutine implementation to use lib/fiber.sx (make-fiber,
fiber-resume, fiber-done?) instead of eagerly running the proc body and
collecting all yields into a list. Each coroutine is now a live fiber —
calls to the coro command invoke fiber-resume, yield suspends via call/cc.

- make-tcl-interp: remove :coroutines/:in-coro/:coro-yields, add :coro-yield-fn nil
- tcl-cmd-yield: calls :coro-yield-fn (fiber's yield fn) to truly suspend
- tcl-cmd-yieldto: same pattern, yields "" to resumer
- make-coro-cmd: takes fiber (not coro-name), calls fiber-resume on each invoke
- tcl-cmd-coroutine: creates a fiber whose body runs the proc with :coro-yield-fn set
- tcl-call-proc result merge: drop :coro-yields/:coroutines propagation
- test.sh: load lib/fiber.sx before lib/tcl/runtime.sx in epoch 4

All 337/337 tests pass including all 20 coro tests.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 17:30:47 +00:00
35511db15b tcl: array get/set/names/size/exists/unset commands (+8 tests, 337 total)
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 45s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 16:29:28 +00:00
40ce4df6b1 tcl: apply command — anonymous proc call reusing tcl-call-proc frame machinery
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 44s
2026-05-06 15:37:26 +00:00
0cc36450c4 tcl: regexp + regsub commands wrapping SX regex primitives
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 43s
regexp: -nocase/-all/-inline flags, optional matchVar + subgroup var args.
regsub: -all/-nocase flags, optional varName (stores result + returns count)
or inline use (returns result string). Both wrap make-regexp/regexp-match/
regexp-match-all/regexp-replace/regexp-replace-all. 329/329 tests green.
2026-05-06 15:31:36 +00:00
21e8e51174 tcl: float expr — tcl-parse-num + float-aware binop/unary/pow/funcs
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 16s
parse-int "2.0" returns nil in SX (strict integer parse); fixed by adding
tcl-num-float? (char scan for ./e/E) and tcl-parse-num (routes to
parse-float when float-shaped). Applied in tcl-apply-binop (all arith +
comparisons), tcl-apply-func (parse-float for all math args), unary minus,
and tcl-expr-parse-power (**). Real sqrt/floor/ceil/round/pow/sin/cos/tan/
exp/log now used instead of integer stubs. Integer division still truncates
when both operands are integer-shaped. 329/329 tests green.
2026-05-06 15:20:10 +00:00
2c61be39de tcl: Phase 6 coroutines + clock/file stubs + idiom corpus (+40 tests, 329 total)
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Has been cancelled
- Coroutines (generator-style): coroutine/yield/yieldto commands; eager yield
  collection during body execution, pop-on-call dispatch via registered command
  closures; coro-yields + coroutines threaded through tcl-call-proc
- info exists varname (plus hostname/script/tclversion stubs)
- clock seconds/milliseconds/format/scan stubs
- File I/O stubs: open/close/read/eof/seek/tell/flush + file subcommands
- format command: full %-specifier parsing with flags, width, zero-pad, left-align
- Fixed dict set/unset/incr/append/update to use tcl-var-get (upvar alias aware)
- Fixed lappend and append to use tcl-var-get for reading (upvar alias aware)
- 20 coroutine tests (coro.sx) + 20 idiom corpus tests (idioms.sx)
- event-loop.tcl program: cooperative scheduler demo using coroutines
- Note: coroutines eagerly collect yields (generator-style, not true suspension)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 11:05:28 +00:00
23c44cf6cf tcl: Phase 5 namespaces + ensembles (+22 tests, 289 total)
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Has been cancelled
Implements namespace eval, current, which, exists, delete, export,
import, forget, path, and ensemble create (auto-map + -map). Procs
defined inside namespace eval are stored as fully-qualified names
(::ns::proc), resolved relative to the calling namespace at lookup
time. Proc bodies execute in their defining namespace so sibling
calls work without qualification.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 10:21:21 +00:00
d295ab8463 tcl: Phase 4 error handling — catch/try/throw/return-code (+39 tests, 267 total)
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Has been cancelled
Implements catch, throw, try, return -code options, and error with
errorinfo/errorcode fields. catch runs sub-script isolated, captures
result and exit code (0-4); try dispatches on/finally clauses;
throw sets code 1 with errorcode; return -code parses flag options.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 09:58:32 +00:00
eb5babaf99 tcl: proc + uplevel + upvar + global + variable + info (+19 tests, 225 total)
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 48s
Phase 3 headline feature: everything falls out of SX's first-class env chain.
- make-tcl-interp extended with :frame-stack and :procs fields
- proc: user-defined commands with param binding, rest args, isolated scope
- uplevel: run script in ancestor frame with correct frame propagation
- upvar: alias local name to remote frame variable (get/set follow alias)
- global/variable: sugar for upvar #0
- info: level, vars, locals, globals, commands, procs, args, body
- tcl-call-proc propagates updated frames back to caller after proc returns
- test.sh timeout bumped to 90s for larger runtime

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 09:30:28 +00:00
263d9aae68 tcl: dict commands — 13 subcommands (+24 tests, 206 total)
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 13s
Implements tcl-cmd-dict with create/get/set/unset/exists/keys/values/
size/for/update/merge/incr/append subcommands, plus helpers
tcl-dict-to-pairs, tcl-dict-from-pairs, tcl-dict-get, tcl-dict-set-pair,
tcl-dict-unset-key. Registers "dict" in make-default-tcl-interp.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 09:00:13 +00:00
7b11f3d44a tcl: list commands — 12 commands (+26 tests, 182 total)
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Has been cancelled
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 08:54:24 +00:00
9ed3e4faaf tcl: string command — 16 subcommands + 29 tests (156 total)
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Has been cancelled
Implements tcl-cmd-string covering length, index, range, compare, match
(glob * and ?), toupper, tolower, trim/trimleft/trimright, map, repeat,
first, last, is (integer/double/alpha/alnum/digit/space/upper/lower/boolean),
and cat. All 156 tcl tests pass (parse: 67, eval: 89).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 08:48:43 +00:00
ac013c9381 tcl: expr mini-language — recursive descent parser (+20 tests, 127 total)
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 42s
Replaces 3-token flat evaluator with full recursive descent parser:
operator precedence, parentheses, unary ops, ** power, function calls
(abs/sqrt/pow/max/min/int/double), expression tokenizer for dense syntax.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 08:43:02 +00:00
c8d7fdd59a tcl: Phase 2 core commands — if/while/for/foreach/switch/break/continue/return/error/expr (+20 tests, 107 total)
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 16s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-26 14:40:48 +00:00
82da16e4bb tcl: Phase 2 eval engine — tcl-eval-script + set/puts/incr/append (+20 tests, 87 total)
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 17s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-26 14:02:52 +00:00