Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 56s
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).
405 lines
9.7 KiB
Plaintext
405 lines
9.7 KiB
Plaintext
; End-to-end pipeline tests: source string → tokenize → parse → eval-ast → array.
|
||
; Verifies the full stack as a single function call (apl-run).
|
||
|
||
(define mkrv (fn (arr) (get arr :ravel)))
|
||
(define mksh (fn (arr) (get arr :shape)))
|
||
|
||
; ---------- scalars ----------
|
||
|
||
(apl-test "apl-run \"42\" → scalar 42" (mkrv (apl-run "42")) (list 42))
|
||
|
||
(apl-test "apl-run \"¯7\" → scalar -7" (mkrv (apl-run "¯7")) (list -7))
|
||
|
||
; ---------- strands ----------
|
||
|
||
(apl-test
|
||
"apl-run \"1 2 3\" → vector"
|
||
(mkrv (apl-run "1 2 3"))
|
||
(list 1 2 3))
|
||
|
||
(apl-test "apl-run \"1 2 3\" shape" (mksh (apl-run "1 2 3")) (list 3))
|
||
|
||
; ---------- dyadic arithmetic ----------
|
||
|
||
(apl-test "apl-run \"2 + 3\" → 5" (mkrv (apl-run "2 + 3")) (list 5))
|
||
|
||
(apl-run "2 × 3 + 4") ; right-to-left
|
||
|
||
(apl-test
|
||
"apl-run \"2 × 3 + 4\" → 14 (right-to-left)"
|
||
(mkrv (apl-run "2 × 3 + 4"))
|
||
(list 14))
|
||
|
||
(apl-test
|
||
"apl-run \"1 2 3 + 4 5 6\" → 5 7 9"
|
||
(mkrv (apl-run "1 2 3 + 4 5 6"))
|
||
(list 5 7 9))
|
||
|
||
(apl-test
|
||
"apl-run \"3 × 1 2 3 4\" → scalar broadcast"
|
||
(mkrv (apl-run "3 × 1 2 3 4"))
|
||
(list 3 6 9 12))
|
||
|
||
; ---------- monadic primitives ----------
|
||
|
||
(apl-test
|
||
"apl-run \"⍳5\" → 1..5"
|
||
(mkrv (apl-run "⍳5"))
|
||
(list 1 2 3 4 5))
|
||
|
||
(apl-test
|
||
"apl-run \"-3\" → -3 (monadic negate)"
|
||
(mkrv (apl-run "-3"))
|
||
(list -3))
|
||
|
||
(apl-test
|
||
"apl-run \"⌈/ 1 3 9 5 7\" → 9 (max-reduce)"
|
||
(mkrv (apl-run "⌈/ 1 3 9 5 7"))
|
||
(list 9))
|
||
|
||
(apl-test
|
||
"apl-run \"⌊/ 4 7 2 9 1 3\" → 1 (min-reduce)"
|
||
(mkrv (apl-run "⌊/ 4 7 2 9 1 3"))
|
||
(list 1))
|
||
|
||
; ---------- operators ----------
|
||
|
||
(apl-test "apl-run \"+/⍳5\" → 15" (mkrv (apl-run "+/⍳5")) (list 15))
|
||
|
||
(apl-test "apl-run \"×/⍳5\" → 120" (mkrv (apl-run "×/⍳5")) (list 120))
|
||
|
||
(apl-test
|
||
"apl-run \"⌈/3 1 4 1 5 9 2\" → 9"
|
||
(mkrv (apl-run "⌈/3 1 4 1 5 9 2"))
|
||
(list 9))
|
||
|
||
(apl-test
|
||
"apl-run \"+\\\\⍳5\" → triangular numbers"
|
||
(mkrv (apl-run "+\\⍳5"))
|
||
(list 1 3 6 10 15))
|
||
|
||
; ---------- outer / inner products ----------
|
||
|
||
(apl-test
|
||
"apl-run \"1 2 3 ∘.× 1 2 3\" → mult table values"
|
||
(mkrv (apl-run "1 2 3 ∘.× 1 2 3"))
|
||
(list 1 2 3 2 4 6 3 6 9))
|
||
|
||
(apl-test
|
||
"apl-run \"1 2 3 +.× 4 5 6\" → dot product 32"
|
||
(mkrv (apl-run "1 2 3 +.× 4 5 6"))
|
||
(list 32))
|
||
|
||
; ---------- shape ----------
|
||
|
||
(apl-test
|
||
"apl-run \"⍴ 1 2 3 4 5\" → 5"
|
||
(mkrv (apl-run "⍴ 1 2 3 4 5"))
|
||
(list 5))
|
||
|
||
(apl-test "apl-run \"⍴⍳10\" → 10" (mkrv (apl-run "⍴⍳10")) (list 10))
|
||
|
||
; ---------- comparison ----------
|
||
|
||
(apl-test "apl-run \"3 < 5\" → 1" (mkrv (apl-run "3 < 5")) (list 1))
|
||
|
||
(apl-test "apl-run \"5 = 5\" → 1" (mkrv (apl-run "5 = 5")) (list 1))
|
||
|
||
(apl-test
|
||
"apl-run \"1 2 3 = 1 0 3\" → 1 0 1"
|
||
(mkrv (apl-run "1 2 3 = 1 0 3"))
|
||
(list 1 0 1))
|
||
|
||
; ---------- famous one-liners ----------
|
||
|
||
(apl-test
|
||
"apl-run \"+/(⍳10)\" → sum 1..10 = 55"
|
||
(mkrv (apl-run "+/(⍳10)"))
|
||
(list 55))
|
||
|
||
(apl-test
|
||
"apl-run \"×/⍳10\" → 10! = 3628800"
|
||
(mkrv (apl-run "×/⍳10"))
|
||
(list 3628800))
|
||
|
||
(apl-test "apl-run \"⎕IO\" → 1" (mkrv (apl-run "⎕IO")) (list 1))
|
||
|
||
(apl-test "apl-run \"⎕ML\" → 1" (mkrv (apl-run "⎕ML")) (list 1))
|
||
|
||
(apl-test "apl-run \"⎕FR\" → 1248" (mkrv (apl-run "⎕FR")) (list 1248))
|
||
|
||
(apl-test "apl-run \"⎕TS\" shape (7)" (mksh (apl-run "⎕TS")) (list 7))
|
||
|
||
(apl-test "apl-run \"⎕FMT 42\" → \"42\"" (apl-run "⎕FMT 42") "42")
|
||
|
||
(apl-test
|
||
"apl-run \"⎕FMT 1 2 3\" → \"1 2 3\""
|
||
(apl-run "⎕FMT 1 2 3")
|
||
"1 2 3")
|
||
|
||
(apl-test
|
||
"apl-run \"⎕FMT ⍳5\" → \"1 2 3 4 5\""
|
||
(apl-run "⎕FMT ⍳5")
|
||
"1 2 3 4 5")
|
||
|
||
(apl-test "apl-run \"⎕IO + 4\" → 5" (mkrv (apl-run "⎕IO + 4")) (list 5))
|
||
|
||
(apl-test
|
||
"apl-run \"(10 20 30 40 50)[3]\" → 30"
|
||
(mkrv (apl-run "(10 20 30 40 50)[3]"))
|
||
(list 30))
|
||
|
||
(apl-test
|
||
"apl-run \"(⍳10)[5]\" → 5"
|
||
(mkrv (apl-run "(⍳10)[5]"))
|
||
(list 5))
|
||
|
||
(apl-test
|
||
"apl-run \"A ← 100 200 300 ⋄ A[2]\" → 200"
|
||
(mkrv (apl-run "A ← 100 200 300 ⋄ A[2]"))
|
||
(list 200))
|
||
|
||
(apl-test
|
||
"apl-run \"V ← ⍳10 ⋄ V[3]\" → 3"
|
||
(mkrv (apl-run "V ← ⍳10 ⋄ V[3]"))
|
||
(list 3))
|
||
|
||
(apl-test
|
||
"apl-run \"(10 20 30)[1]\" → 10 (1-indexed)"
|
||
(mkrv (apl-run "(10 20 30)[1]"))
|
||
(list 10))
|
||
|
||
(apl-test
|
||
"apl-run \"V ← 10 20 30 40 50 ⋄ V[3] + 1\" → 31"
|
||
(mkrv (apl-run "V ← 10 20 30 40 50 ⋄ V[3] + 1"))
|
||
(list 31))
|
||
|
||
(apl-test
|
||
"apl-run \"(⍳5)[3] × 7\" → 21"
|
||
(mkrv (apl-run "(⍳5)[3] × 7"))
|
||
(list 21))
|
||
|
||
(apl-test "decimal: 3.7 → 3.7" (mkrv (apl-run "3.7")) (list 3.7))
|
||
|
||
(apl-test "decimal: ¯2.5 → -2.5" (mkrv (apl-run "¯2.5")) (list -2.5))
|
||
|
||
(apl-test "decimal: 1.5 + 2.5 → 4" (mkrv (apl-run "1.5 + 2.5")) (list 4))
|
||
|
||
(apl-test "decimal: ⌊3.7 → 3" (mkrv (apl-run "⌊ 3.7")) (list 3))
|
||
|
||
(apl-test "decimal: ⌈3.7 → 4" (mkrv (apl-run "⌈ 3.7")) (list 4))
|
||
|
||
(apl-test
|
||
"⎕← scalar passthrough"
|
||
(mkrv (apl-run "⎕← 42"))
|
||
(list 42))
|
||
|
||
(apl-test
|
||
"⎕← vector passthrough"
|
||
(mkrv (apl-run "⎕← 1 2 3"))
|
||
(list 1 2 3))
|
||
|
||
(apl-test
|
||
"string: 'abc' → 3-char vector"
|
||
(mkrv (apl-run "'abc'"))
|
||
(list "a" "b" "c"))
|
||
|
||
(apl-test "string: 'a' is rank-0 scalar" (mksh (apl-run "'a'")) (list))
|
||
|
||
(apl-test "string: 'hello' shape (5)" (mksh (apl-run "'hello'")) (list 5))
|
||
|
||
(apl-test
|
||
"named-fn: f ← {⍺+⍵} ⋄ 3 f 4 → 7"
|
||
(mkrv (apl-run "f ← {⍺+⍵} ⋄ 3 f 4"))
|
||
(list 7))
|
||
|
||
(apl-test
|
||
"named-fn monadic: sq ← {⍵×⍵} ⋄ sq 7 → 49"
|
||
(mkrv (apl-run "sq ← {⍵×⍵} ⋄ sq 7"))
|
||
(list 49))
|
||
|
||
(apl-test
|
||
"named-fn dyadic: hyp ← {((⍺×⍺)+⍵×⍵)} ⋄ 3 hyp 4 → 25"
|
||
(mkrv (apl-run "hyp ← {((⍺×⍺)+⍵×⍵)} ⋄ 3 hyp 4"))
|
||
(list 25))
|
||
|
||
(apl-test
|
||
"named-fn: dbl ← {⍵+⍵} ⋄ dbl ⍳5"
|
||
(mkrv (apl-run "dbl ← {⍵+⍵} ⋄ dbl ⍳5"))
|
||
(list 2 4 6 8 10))
|
||
|
||
(apl-test
|
||
"named-fn factorial via ∇ recursion"
|
||
(mkrv (apl-run "fact ← {0=⍵:1 ⋄ ⍵×∇⍵-1} ⋄ fact 5"))
|
||
(list 120))
|
||
|
||
(apl-test
|
||
"named-fn used twice in expr: dbl ← {⍵+⍵} ⋄ (dbl 3) + dbl 4"
|
||
(mkrv (apl-run "dbl ← {⍵+⍵} ⋄ (dbl 3) + dbl 4"))
|
||
(list 14))
|
||
|
||
(apl-test
|
||
"named-fn with vector arg: neg ← {-⍵} ⋄ neg 1 2 3"
|
||
(mkrv (apl-run "neg ← {-⍵} ⋄ neg 1 2 3"))
|
||
(list -1 -2 -3))
|
||
|
||
(apl-test
|
||
"multi-axis: M[2;2] → center"
|
||
(mkrv (apl-run "M ← (3 3) ⍴ ⍳9 ⋄ M[2;2]"))
|
||
(list 5))
|
||
|
||
(apl-test
|
||
"multi-axis: M[1;] → first row"
|
||
(mkrv (apl-run "M ← (3 3) ⍴ ⍳9 ⋄ M[1;]"))
|
||
(list 1 2 3))
|
||
|
||
(apl-test
|
||
"multi-axis: M[;2] → second column"
|
||
(mkrv (apl-run "M ← (3 3) ⍴ ⍳9 ⋄ M[;2]"))
|
||
(list 2 5 8))
|
||
|
||
(apl-test
|
||
"multi-axis: M[1 2;1 2] → 2x2 block"
|
||
(mkrv (apl-run "M ← (2 3) ⍴ ⍳6 ⋄ M[1 2;1 2]"))
|
||
(list 1 2 4 5))
|
||
|
||
(apl-test
|
||
"multi-axis: M[1 2;1 2] shape (2 2)"
|
||
(mksh (apl-run "M ← (2 3) ⍴ ⍳6 ⋄ M[1 2;1 2]"))
|
||
(list 2 2))
|
||
|
||
(apl-test
|
||
"multi-axis: M[;] full matrix"
|
||
(mkrv (apl-run "M ← (2 2) ⍴ 10 20 30 40 ⋄ M[;]"))
|
||
(list 10 20 30 40))
|
||
|
||
(apl-test
|
||
"multi-axis: M[1;] shape collapsed"
|
||
(mksh (apl-run "M ← (3 3) ⍴ ⍳9 ⋄ M[1;]"))
|
||
(list 3))
|
||
|
||
(apl-test
|
||
"multi-axis: select all rows of column 3"
|
||
(mkrv (apl-run "M ← (4 3) ⍴ 1 2 3 4 5 6 7 8 9 10 11 12 ⋄ M[;3]"))
|
||
(list 3 6 9 12))
|
||
|
||
(apl-test
|
||
"train: mean = (+/÷≢) on 1..5"
|
||
(mkrv (apl-run "(+/÷≢) 1 2 3 4 5"))
|
||
(list 3))
|
||
|
||
(apl-test
|
||
"train: mean of 2 4 6 8 10"
|
||
(mkrv (apl-run "(+/÷≢) 2 4 6 8 10"))
|
||
(list 6))
|
||
|
||
(apl-test
|
||
"train 2-atop: (- ⌊) 5 → -5"
|
||
(mkrv (apl-run "(- ⌊) 5"))
|
||
(list -5))
|
||
|
||
(apl-test
|
||
"train 3-fork dyadic: 2(+×-)5 → -21"
|
||
(mkrv (apl-run "2 (+ × -) 5"))
|
||
(list -21))
|
||
|
||
(apl-test
|
||
"train: range = (⌈/-⌊/) on vector"
|
||
(mkrv (apl-run "(⌈/-⌊/) 3 1 4 1 5 9 2 6"))
|
||
(list 8))
|
||
|
||
(apl-test
|
||
"train: mean of ⍳10 has shape ()"
|
||
(mksh (apl-run "(+/÷≢) ⍳10"))
|
||
(list))
|
||
|
||
(apl-test
|
||
"compress: 1 0 1 0 1 / 10 20 30 40 50"
|
||
(mkrv (apl-run "1 0 1 0 1 / 10 20 30 40 50"))
|
||
(list 10 30 50))
|
||
|
||
(apl-test
|
||
"compress: empty mask → empty"
|
||
(mkrv (apl-run "0 0 0 / 1 2 3"))
|
||
(list))
|
||
|
||
(apl-test
|
||
"primes via classic idiom (multi-stmt)"
|
||
(mkrv (apl-run "P ← ⍳ 30 ⋄ (2 = +⌿ 0 = P ∘.| P) / P"))
|
||
(list 2 3 5 7 11 13 17 19 23 29))
|
||
|
||
(apl-test
|
||
"primes via classic idiom (n=20)"
|
||
(mkrv (apl-run "P ← ⍳ 20 ⋄ (2 = +⌿ 0 = P ∘.| P) / P"))
|
||
(list 2 3 5 7 11 13 17 19))
|
||
|
||
(apl-test
|
||
"compress: filter even values"
|
||
(mkrv (apl-run "(0 = 2 | 1 2 3 4 5 6) / 1 2 3 4 5 6"))
|
||
(list 2 4 6))
|
||
|
||
(apl-test "inline-assign: x ← 5" (mkrv (apl-run "x ← 5")) (list 5))
|
||
|
||
(apl-test
|
||
"inline-assign: (2×x) + x←10 → 30"
|
||
(mkrv (apl-run "(2 × x) + x ← 10"))
|
||
(list 30))
|
||
|
||
(apl-test
|
||
"inline-assign primes one-liner: (2=+⌿0=a∘.|a)/a←⍳30"
|
||
(mkrv (apl-run "(2 = +⌿ 0 = a ∘.| a) / a ← ⍳ 30"))
|
||
(list 2 3 5 7 11 13 17 19 23 29))
|
||
|
||
(apl-test
|
||
"inline-assign: x is reusable — x + x ← 7 → 14"
|
||
(mkrv (apl-run "x + x ← 7"))
|
||
(list 14))
|
||
|
||
(apl-test
|
||
"inline-assign in dfn: f ← {x + x ← ⍵} ⋄ f 8 → 16"
|
||
(mkrv (apl-run "f ← {x + x ← ⍵} ⋄ f 8"))
|
||
(list 16))
|
||
|
||
(begin (apl-rng-seed! 42) nil)
|
||
|
||
(apl-test
|
||
"?10 with seed 42 → 8 (deterministic)"
|
||
(mkrv (apl-run "?10"))
|
||
(list 8))
|
||
|
||
(apl-test "?10 next call → 5" (mkrv (apl-run "?10")) (list 5))
|
||
|
||
(apl-test
|
||
"?100 stays in range"
|
||
(let ((v (first (mkrv (apl-run "?100"))))) (and (>= v 1) (<= v 100)))
|
||
true)
|
||
|
||
(begin (apl-rng-seed! 42) nil)
|
||
|
||
(apl-test
|
||
"?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))
|