; 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 returns primes count"
  (mksh
    (apl-run
      (str (file-read "lib/apl/tests/programs/primes.apl") " ⋄ primes 30")))
  (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)

(apl-test
  "⍉ monadic transpose 2x3 → 3x2"
  (mkrv (apl-run "⍉ (2 3) ⍴ ⍳6"))
  (list 1 4 2 5 3 6))

(apl-test
  "⍉ transpose shape (3 2)"
  (mksh (apl-run "⍉ (2 3) ⍴ ⍳6"))
  (list 3 2))

(apl-test "⊢ monadic identity" (mkrv (apl-run "⊢ 1 2 3")) (list 1 2 3))

(apl-test
  "5 ⊣ 1 2 3 → 5 (left)"
  (mkrv (apl-run "5 ⊣ 1 2 3"))
  (list 5))

(apl-test
  "5 ⊢ 1 2 3 → 1 2 3 (right)"
  (mkrv (apl-run "5 ⊢ 1 2 3"))
  (list 1 2 3))

(apl-test "⍕ 42 → \"42\" (alias for ⎕FMT)" (apl-run "⍕ 42") "42")

(begin
  (apl-test
    "⍸ where: indices of truthy cells"
    (mkrv (apl-run "⍸ 0 1 0 1 1"))
    (list 2 4 5))
  (apl-test
    "⍸ where: leading truthy"
    (mkrv (apl-run "⍸ 1 0 0 1 1"))
    (list 1 4 5))
  (apl-test
    "⍸ where: all-zero → empty"
    (mkrv (apl-run "⍸ 0 0 0"))
    (list))
  (apl-test
    "⍸ where: all-truthy"
    (mkrv (apl-run "⍸ 1 1 1"))
    (list 1 2 3))
  (apl-test
    "⍸ where: ⎕IO=1 (1-based)"
    (mkrv (apl-run "⍸ (⍳5)=3"))
    (list 3))
  (apl-test
    "⍸ interval-index: 2 4 6 ⍸ 5 → 2"
    (mkrv (apl-run "2 4 6 ⍸ 5"))
    (list 2))
  (apl-test
    "⍸ interval-index: 2 4 6 ⍸ 1 3 5 6 7 → 0 1 2 3 3"
    (mkrv (apl-run "2 4 6 ⍸ 1 3 5 6 7"))
    (list 0 1 2 3 3))
  (apl-test
    "⍸ interval-index: ⍳5 ⍸ 3 → 3"
    (mkrv (apl-run "(⍳5) ⍸ 3"))
    (list 3))
  (apl-test
    "⍸ interval-index: y below all → 0"
    (mkrv (apl-run "10 20 30 ⍸ 5"))
    (list 0))
  (apl-test
    "⍸ interval-index: y above all → len breaks"
    (mkrv (apl-run "10 20 30 ⍸ 100"))
    (list 3)))

(begin
  (apl-test
    "∪ unique: dedup keeps first-occurrence order"
    (mkrv (apl-run "∪ 1 2 1 3 2 1 4"))
    (list 1 2 3 4))
  (apl-test
    "∪ unique: already-unique unchanged"
    (mkrv (apl-run "∪ 5 4 3 2 1"))
    (list 5 4 3 2 1))
  (apl-test "∪ unique: scalar" (mkrv (apl-run "∪ 7")) (list 7))
  (apl-test
    "∪ unique: string mississippi → misp"
    (mkrv (apl-run "∪ 'mississippi'"))
    (list "m" "i" "s" "p"))
  (apl-test
    "∪ union: 1 2 3 ∪ 3 4 5 → 1 2 3 4 5"
    (mkrv (apl-run "1 2 3 ∪ 3 4 5"))
    (list 1 2 3 4 5))
  (apl-test
    "∪ union: dedups left side too"
    (mkrv (apl-run "1 2 1 ∪ 1 3 2"))
    (list 1 2 3))
  (apl-test
    "∪ union: disjoint → catenated"
    (mkrv (apl-run "1 2 ∪ 3 4"))
    (list 1 2 3 4))
  (apl-test
    "∩ intersection: 1 2 3 4 ∩ 2 4 6 → 2 4"
    (mkrv (apl-run "1 2 3 4 ∩ 2 4 6"))
    (list 2 4))
  (apl-test
    "∩ intersection: disjoint → empty"
    (mkrv (apl-run "1 2 3 ∩ 4 5 6"))
    (list))
  (apl-test
    "∩ intersection: preserves left order"
    (mkrv (apl-run "(⍳5) ∩ 5 3 1"))
    (list 1 3 5))
  (apl-test
    "∩ intersection: identical"
    (mkrv (apl-run "1 2 3 ∩ 1 2 3"))
    (list 1 2 3))
  (apl-test
    "∪/∩ identity: A ∪ A = ∪A"
    (mkrv (apl-run "1 2 1 ∪ 1 2 1"))
    (list 1 2)))

(begin
  (apl-test
    "⊥ decode: 2 2 2 ⊥ 1 0 1 → 5"
    (mkrv (apl-run "2 2 2 ⊥ 1 0 1"))
    (list 5))
  (apl-test
    "⊥ decode: 10 10 10 ⊥ 1 2 3 → 123"
    (mkrv (apl-run "10 10 10 ⊥ 1 2 3"))
    (list 123))
  (apl-test
    "⊥ decode: 24 60 60 ⊥ 2 3 4 → 7384 (mixed-radix HMS)"
    (mkrv (apl-run "24 60 60 ⊥ 2 3 4"))
    (list 7384))
  (apl-test
    "⊥ decode: scalar base 2 ⊥ 1 0 1 0 → 10"
    (mkrv (apl-run "2 ⊥ 1 0 1 0"))
    (list 10))
  (apl-test
    "⊥ decode: 16 16 ⊥ 15 15 → 255"
    (mkrv (apl-run "16 16 ⊥ 15 15"))
    (list 255))
  (apl-test
    "⊤ encode: 2 2 2 ⊤ 5 → 1 0 1"
    (mkrv (apl-run "2 2 2 ⊤ 5"))
    (list 1 0 1))
  (apl-test
    "⊤ encode: 24 60 60 ⊤ 7384 → 2 3 4 (HMS)"
    (mkrv (apl-run "24 60 60 ⊤ 7384"))
    (list 2 3 4))
  (apl-test
    "⊤ encode: 2 2 2 2 ⊤ 13 → 1 1 0 1"
    (mkrv (apl-run "2 2 2 2 ⊤ 13"))
    (list 1 1 0 1))
  (apl-test
    "⊤ encode: 10 10 ⊤ 42 → 4 2"
    (mkrv (apl-run "10 10 ⊤ 42"))
    (list 4 2))
  (apl-test
    "⊤ encode: round-trip B⊥(B⊤N) = N"
    (mkrv (apl-run "24 60 60 ⊥ 24 60 60 ⊤ 7384"))
    (list 7384))
  (apl-test
    "⊥ decode: round-trip B⊤(B⊥V) = V"
    (mkrv (apl-run "2 2 2 ⊤ 2 2 2 ⊥ 1 0 1"))
    (list 1 0 1)))

(begin
  (define
    mk-parts
    (fn (s) (map (fn (p) (get p :ravel)) (get (apl-run s) :ravel))))
  (apl-test
    "⊆ partition: 1 1 0 1 1 ⊆ 'abcde' → ('ab' 'de')"
    (mk-parts "1 1 0 1 1 ⊆ 'abcde'")
    (list (list "a" "b") (list "d" "e")))
  (apl-test
    "⊆ partition: 1 0 0 1 1 ⊆ ⍳5 → ((1) (4 5))"
    (mk-parts "1 0 0 1 1 ⊆ ⍳5")
    (list (list 1) (list 4 5)))
  (apl-test
    "⊆ partition: all-zero mask → empty"
    (len (get (apl-run "0 0 0 ⊆ 1 2 3") :ravel))
    0)
  (apl-test
    "⊆ partition: all-one mask → single partition"
    (mk-parts "1 1 1 ⊆ 7 8 9")
    (list (list 7 8 9)))
  (apl-test
    "⊆ partition: strict increase 1 2 starts new"
    (mk-parts "1 2 ⊆ 10 20")
    (list (list 10) (list 20)))
  (apl-test
    "⊆ partition: same level continues 2 2 → one partition"
    (mk-parts "2 2 ⊆ 10 20")
    (list (list 10 20)))
  (apl-test
    "⊆ partition: 0 separates"
    (mk-parts "1 1 0 0 1 ⊆ 1 2 3 4 5")
    (list (list 1 2) (list 5)))
  (apl-test
    "⊆ partition: outer length matches partition count"
    (len (get (apl-run "1 0 1 0 1 ⊆ ⍳5") :ravel))
    3))

(begin
  (apl-test
    "⍎ execute: ⍎ '1 + 2' → 3"
    (mkrv (apl-run "⍎ '1 + 2'"))
    (list 3))
  (apl-test
    "⍎ execute: ⍎ '+/⍳10' → 55"
    (mkrv (apl-run "⍎ '+/⍳10'"))
    (list 55))
  (apl-test
    "⍎ execute: ⍎ '⌈/ 1 3 9 5 7' → 9"
    (mkrv (apl-run "⍎ '⌈/ 1 3 9 5 7'"))
    (list 9))
  (apl-test
    "⍎ execute: ⍎ '⍳5' → 1..5"
    (mkrv (apl-run "⍎ '⍳5'"))
    (list 1 2 3 4 5))
  (apl-test
    "⍎ execute: ⍎ '×/⍳5' → 120"
    (mkrv (apl-run "⍎ '×/⍳5'"))
    (list 120))
  (apl-test
    "⍎ execute: round-trip ⍎ ⎕FMT 42 → 42"
    (mkrv (apl-run "⍎ ⎕FMT 42"))
    (list 42))
  (apl-test
    "⍎ execute: nested ⍎ ⍎"
    (mkrv (apl-run "⍎ '⍎ ''2 × 3'''"))
    (list 6))
  (apl-test
    "⍎ execute: with assignment side-effect"
    (mkrv (apl-run "⍎ 'q ← 99 ⋄ q + 1'"))
    (list 100)))

(begin
  (apl-test
    "het-inner: 1 ⍵ ∨.∧ X — result is enclosed (5 5)"
    (let
      ((r (apl-run "B ← 5 5 ⍴ 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 ⋄ X ← 3 4 = +/ +/ ¯1 0 1 ∘.⊖ ¯1 0 1 ⌽¨ ⊂B ⋄ 1 B ∨.∧ X")))
      (list
        (len (get r :shape))
        (= (type-of (first (get r :ravel))) "dict")))
    (list 0 true))
  (apl-test
    "het-inner: ⊃ unwraps to (5 5) board"
    (mksh
      (apl-run
        "B ← 5 5 ⍴ 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 ⋄ X ← 3 4 = +/ +/ ¯1 0 1 ∘.⊖ ¯1 0 1 ⌽¨ ⊂B ⋄ ⊃ 1 B ∨.∧ X"))
    (list 5 5))
  (apl-test
    "het-inner: homogeneous inner product unaffected"
    (mkrv (apl-run "1 2 3 +.× 4 5 6"))
    (list 32))
  (apl-test
    "het-inner: matrix inner product unaffected"
    (mkrv (apl-run "(2 2 ⍴ 1 2 3 4) +.× 2 2 ⍴ 5 6 7 8"))
    (list 19 22 43 50)))
