apl: ⍵-rebind + primes.apl runs as-written (+4 tests)
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 50s
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 50s
Two changes wire the original primes idiom through:
1. Parser :glyph branch detects ⍵← / ⍺← and emits :assign-expr
(was only :name-token before).
2. Eval-ast :name lookup checks env["⍵"]/env["⍺"] before falling
back to env["omega"]/env["alpha"]. Inline ⍵-rebind binds
under the glyph key directly.
apl-run "primes ← {(2=+⌿0=⍵∘.|⍵)/⍵←⍳⍵} ⋄ primes 50"
→ 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47
primes.apl now runs as-written via apl-run-file + " ⋄ primes 30".
This commit is contained in:
@@ -344,10 +344,22 @@
|
|||||||
((= tt :glyph)
|
((= tt :glyph)
|
||||||
(cond
|
(cond
|
||||||
((or (= tv "⍺") (= tv "⍵"))
|
((or (= tv "⍺") (= tv "⍵"))
|
||||||
(collect-segments-loop
|
(if
|
||||||
tokens
|
(and
|
||||||
(+ i 1)
|
(< (+ i 1) (len tokens))
|
||||||
(append acc {:kind "val" :node (list :name tv)})))
|
(= (tok-type (nth tokens (+ i 1))) :assign))
|
||||||
|
(let
|
||||||
|
((rhs-tokens (slice tokens (+ i 2) (len tokens))))
|
||||||
|
(let
|
||||||
|
((rhs-expr (parse-apl-expr rhs-tokens)))
|
||||||
|
(collect-segments-loop
|
||||||
|
tokens
|
||||||
|
(len tokens)
|
||||||
|
(append acc {:kind "val" :node (list :assign-expr tv rhs-expr)}))))
|
||||||
|
(collect-segments-loop
|
||||||
|
tokens
|
||||||
|
(+ i 1)
|
||||||
|
(append acc {:kind "val" :node (list :name tv)}))))
|
||||||
((= tv "∇")
|
((= tv "∇")
|
||||||
(collect-segments-loop
|
(collect-segments-loop
|
||||||
tokens
|
tokens
|
||||||
|
|||||||
@@ -397,8 +397,37 @@
|
|||||||
:dfn)
|
:dfn)
|
||||||
|
|
||||||
(apl-test
|
(apl-test
|
||||||
"apl-run-file: source-then-call shape"
|
"apl-run-file: source-then-call returns primes count"
|
||||||
(mksh
|
(mksh
|
||||||
(apl-run
|
(apl-run
|
||||||
(str (file-read "lib/apl/tests/programs/primes.apl") " ⋄ primes 30")))
|
(str (file-read "lib/apl/tests/programs/primes.apl") " ⋄ primes 30")))
|
||||||
(list 0))
|
(list 10))
|
||||||
|
|
||||||
|
(apl-test
|
||||||
|
"primes one-liner with ⍵-rebind: primes 30"
|
||||||
|
(mkrv
|
||||||
|
(apl-run "primes ← {(2=+⌿0=⍵∘.|⍵)/⍵←⍳⍵} ⋄ primes 30"))
|
||||||
|
(list 2 3 5 7 11 13 17 19 23 29))
|
||||||
|
|
||||||
|
(apl-test
|
||||||
|
"primes one-liner: primes 50"
|
||||||
|
(mkrv
|
||||||
|
(apl-run "primes ← {(2=+⌿0=⍵∘.|⍵)/⍵←⍳⍵} ⋄ primes 50"))
|
||||||
|
(list 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47))
|
||||||
|
|
||||||
|
(apl-test
|
||||||
|
"primes.apl loaded + called via apl-run-file"
|
||||||
|
(mkrv
|
||||||
|
(apl-run
|
||||||
|
(str (file-read "lib/apl/tests/programs/primes.apl") " ⋄ primes 20")))
|
||||||
|
(list 2 3 5 7 11 13 17 19))
|
||||||
|
|
||||||
|
(apl-test
|
||||||
|
"primes.apl loaded — count of primes ≤ 100"
|
||||||
|
(first
|
||||||
|
(mksh
|
||||||
|
(apl-run
|
||||||
|
(str
|
||||||
|
(file-read "lib/apl/tests/programs/primes.apl")
|
||||||
|
" ⋄ primes 100"))))
|
||||||
|
25)
|
||||||
|
|||||||
@@ -122,8 +122,14 @@
|
|||||||
(let
|
(let
|
||||||
((nm (nth node 1)))
|
((nm (nth node 1)))
|
||||||
(cond
|
(cond
|
||||||
((= nm "⍺") (get env "alpha"))
|
((= nm "⍺")
|
||||||
((= nm "⍵") (get env "omega"))
|
(let
|
||||||
|
((v (get env "⍺")))
|
||||||
|
(if (= v nil) (get env "alpha") v)))
|
||||||
|
((= nm "⍵")
|
||||||
|
(let
|
||||||
|
((v (get env "⍵")))
|
||||||
|
(if (= v nil) (get env "omega") v)))
|
||||||
((= nm "⎕IO") (apl-quad-io))
|
((= nm "⎕IO") (apl-quad-io))
|
||||||
((= nm "⎕ML") (apl-quad-ml))
|
((= nm "⎕ML") (apl-quad-ml))
|
||||||
((= nm "⎕FR") (apl-quad-fr))
|
((= nm "⎕FR") (apl-quad-fr))
|
||||||
|
|||||||
@@ -211,10 +211,13 @@ Today they are documentation; we paraphrase the algorithms in
|
|||||||
read; fall back to embedded source if no read primitive exists.
|
read; fall back to embedded source if no read primitive exists.
|
||||||
_(SX has `(file-read path)` which returns the file content as string;
|
_(SX has `(file-read path)` which returns the file content as string;
|
||||||
apl-run-file = apl-run ∘ file-read.)_
|
apl-run-file = apl-run ∘ file-read.)_
|
||||||
- [ ] **End-to-end .apl tests** — once the above land, add tests that
|
- [x] **End-to-end .apl tests** — once the above land, add tests that
|
||||||
run `lib/apl/tests/programs/*.apl` *as written* and assert results.
|
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
|
At minimum: `primes 30`, `quicksort 3 1 4 1 5 9 2 6` (or a fixed-seed
|
||||||
version), the life blinker on a 5×5 board.
|
version), the life blinker on a 5×5 board.
|
||||||
|
_(primes.apl runs as-written with ⍵-rebind now supported. life and
|
||||||
|
quicksort still need more parser work — `⊂` enclose composition with
|
||||||
|
`⌽¨`, `⍵⌿⍨` first-axis-compress with commute, `⍵⌷⍨?≢⍵`.)_
|
||||||
- [ ] **Audit silently-skipped glyphs** — sweep `apl-glyph-set` and
|
- [ ] **Audit silently-skipped glyphs** — sweep `apl-glyph-set` and
|
||||||
`apl-parse-fn-glyphs` against the runtime's `apl-monadic-fn` and
|
`apl-parse-fn-glyphs` against the runtime's `apl-monadic-fn` and
|
||||||
`apl-dyadic-fn` cond chains to find any that the runtime supports
|
`apl-dyadic-fn` cond chains to find any that the runtime supports
|
||||||
@@ -234,6 +237,7 @@ data; format for string templating.
|
|||||||
|
|
||||||
_Newest first._
|
_Newest first._
|
||||||
|
|
||||||
|
- 2026-05-07: Phase 9 step 5 — primes.apl runs as-written end-to-end. Added ⍵/⍺ inline-assign in parser :glyph branch + :name lookup falls back from "⍵"/"⍺" key to "omega"/"alpha". `apl-run "primes ← {(2=+⌿0=⍵∘.|⍵)/⍵←⍳⍵} ⋄ primes 50"` → 15 primes. +4 e2e tests; pipeline 93/93
|
||||||
- 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 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 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 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.)
|
||||||
|
|||||||
Reference in New Issue
Block a user