From bf782d9c497c0c100df4b7a2cf534b1f1c4276fc Mon Sep 17 00:00:00 2001 From: giles Date: Thu, 7 May 2026 22:48:21 +0000 Subject: [PATCH] =?UTF-8?q?apl:=20apl-run-file=20path=20=E2=86=92=20array?= =?UTF-8?q?=20(+4=20tests)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Trivial wrapper: apl-run-file = apl-run ∘ file-read, where file-read is built-in to OCaml SX. Tests verify primes.apl, life.apl, quicksort.apl all parse end-to-end (their last form is a :dfn AST). Source-then-call test confirms the loaded file's defined fn is callable, even when the algorithm itself can't fully execute (primes' inline ⍵ rebinding still missing — :glyph-token, not :name-token). --- lib/apl/tests/pipeline.sx | 22 ++++++++++++++++++++++ lib/apl/transpile.sx | 2 ++ plans/apl-on-sx.md | 5 ++++- 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/lib/apl/tests/pipeline.sx b/lib/apl/tests/pipeline.sx index 32bb9679..d998e325 100644 --- a/lib/apl/tests/pipeline.sx +++ b/lib/apl/tests/pipeline.sx @@ -380,3 +380,25 @@ "?10 with re-seed 42 → 8 (reproducible)" (mkrv (apl-run "?10")) (list 8)) + +(apl-test + "apl-run-file: load primes.apl returns dfn AST" + (first (apl-run-file "lib/apl/tests/programs/primes.apl")) + :dfn) + +(apl-test + "apl-run-file: life.apl parses without error" + (first (apl-run-file "lib/apl/tests/programs/life.apl")) + :dfn) + +(apl-test + "apl-run-file: quicksort.apl parses without error" + (first (apl-run-file "lib/apl/tests/programs/quicksort.apl")) + :dfn) + +(apl-test + "apl-run-file: source-then-call shape" + (mksh + (apl-run + (str (file-read "lib/apl/tests/programs/primes.apl") " ⋄ primes 30"))) + (list 0)) diff --git a/lib/apl/transpile.sx b/lib/apl/transpile.sx index 1e69420d..ef8222f2 100644 --- a/lib/apl/transpile.sx +++ b/lib/apl/transpile.sx @@ -551,3 +551,5 @@ (else (error "apl-resolve-dyadic: unknown fn-node tag")))))) (define apl-run (fn (src) (apl-eval-ast (parse-apl src) {}))) + +(define apl-run-file (fn (path) (apl-run (file-read path)))) diff --git a/plans/apl-on-sx.md b/plans/apl-on-sx.md index af805fa9..ea6a1acf 100644 --- a/plans/apl-on-sx.md +++ b/plans/apl-on-sx.md @@ -205,10 +205,12 @@ Today they are documentation; we paraphrase the algorithms in - [x] **`?` (random / roll)** — monadic `?N` returns a random integer in 1..N. Used by quicksort.apl for pivot selection. Add `apl-roll` (deterministic seed for tests) + glyph wiring. -- [ ] **`apl-run-file path → array`** — read the file from disk, strip +- [x] **`apl-run-file path → array`** — read the file from disk, strip the `⍝` comments (already handled by tokenizer), and run. Needs an IO primitive on the SX side. Probe `mcp` / `harness`-style file read; fall back to embedded source if no read primitive exists. + _(SX has `(file-read path)` which returns the file content as string; + apl-run-file = apl-run ∘ file-read.)_ - [ ] **End-to-end .apl tests** — once the above land, add tests that run `lib/apl/tests/programs/*.apl` *as written* and assert results. At minimum: `primes 30`, `quicksort 3 1 4 1 5 9 2 6` (or a fixed-seed @@ -232,6 +234,7 @@ data; format for string templating. _Newest first._ +- 2026-05-07: Phase 9 step 4 — apl-run-file = apl-run ∘ file-read; SX has (file-read path) returning content as string. primes/life/quicksort .apl files now load and parse end-to-end (return :dfn AST). +4 tests - 2026-05-07: Phase 9 step 3 — `?N` random / roll. Top-level mutable apl-rng-state with LCG; apl-rng-seed! for deterministic tests; apl-roll wraps as scalar in 1..N. apl-monadic-fn maps "?" → apl-roll. +4 tests (deterministic with seed 42, range checks) - 2026-05-07: Phase 9 step 2 — inline assignment `(2=+⌿0=a∘.|a)/a←⍳30` runs end-to-end. Parser :name clause detects `name ← rhs`, consumes rest as RHS, emits :assign-expr segment. Eval-ast :dyad/:monad capture env update when their right operand is :assign-expr. +5 tests (one-liner primes via inline assign, x+x←7=14, dfn-internal inline assign, etc.) - 2026-05-07: Phase 9 step 1 — compress-as-fn / and ⌿; collect-segments-loop emits (:fn-glyph "/") when slash stands alone; apl-dyadic-fn dispatches / → apl-compress, ⌿ → apl-compress-first (new helper); classic primes idiom now runs end-to-end: `P ← ⍳ 30 ⋄ (2 = +⌿ 0 = P ∘.| P) / P` → primes; queens(8) test removed again (q(8) climbed to 215s on this server load); +5 tests; 501/501