; Tests for operator handling in apl-eval-ast (Phase 7).
; Manual AST construction; verifies :derived-fn / :outer / :derived-fn2
; route through apl-resolve-monadic / apl-resolve-dyadic correctly.

(define mkrv (fn (arr) (get arr :ravel)))
(define mksh (fn (arr) (get arr :shape)))
(define mknum (fn (n) (list :num n)))
(define mkfg (fn (g) (list :fn-glyph g)))
(define mkmon (fn (g a) (list :monad g a)))
(define mkdyd (fn (g l r) (list :dyad g l r)))
(define mkder (fn (op f) (list :derived-fn op f)))
(define mkdr2 (fn (op f g) (list :derived-fn2 op f g)))
(define mkout (fn (f) (list :outer "∘." f)))

; helper: literal vector AST via :vec (from list of values)
(define mkvec (fn (xs) (cons :vec (map (fn (n) (mknum n)) xs))))

; ---------- monadic operators ----------

(apl-test
  "eval-ast +/ ⍳5 → 15"
  (mkrv
    (apl-eval-ast
      (mkmon (mkder "/" (mkfg "+")) (mkmon (mkfg "⍳") (mknum 5)))
      {}))
  (list 15))

(apl-test
  "eval-ast ×/ ⍳5 → 120"
  (mkrv
    (apl-eval-ast
      (mkmon (mkder "/" (mkfg "×")) (mkmon (mkfg "⍳") (mknum 5)))
      {}))
  (list 120))

(apl-test
  "eval-ast ⌈/ — max reduce"
  (mkrv
    (apl-eval-ast
      (mkmon (mkder "/" (mkfg "⌈")) (mkvec (list 3 1 4 1 5 9 2 6)))
      {}))
  (list 9))

(apl-test
  "eval-ast +\\ scan"
  (mkrv
    (apl-eval-ast
      (mkmon (mkder "\\" (mkfg "+")) (mkvec (list 1 2 3 4 5)))
      {}))
  (list 1 3 6 10 15))

(apl-test
  "eval-ast +⌿ first-axis reduce on vector"
  (mkrv
    (apl-eval-ast
      (mkmon (mkder "⌿" (mkfg "+")) (mkvec (list 1 2 3 4 5)))
      {}))
  (list 15))

(apl-test
  "eval-ast -¨ each-negate"
  (mkrv
    (apl-eval-ast
      (mkmon (mkder "¨" (mkfg "-")) (mkvec (list 1 2 3 4)))
      {}))
  (list -1 -2 -3 -4))

(apl-test
  "eval-ast +⍨ commute (double via x+x)"
  (mkrv
    (apl-eval-ast (mkmon (mkder "⍨" (mkfg "+")) (mknum 7)) {}))
  (list 14))

; ---------- dyadic operators ----------

(apl-test
  "eval-ast outer ∘.× — multiplication table"
  (mkrv
    (apl-eval-ast
      (mkdyd
        (mkout (mkfg "×"))
        (mkvec (list 1 2 3))
        (mkvec (list 1 2 3)))
      {}))
  (list 1 2 3 2 4 6 3 6 9))

(apl-test
  "eval-ast outer ∘.× shape (3 3)"
  (mksh
    (apl-eval-ast
      (mkdyd
        (mkout (mkfg "×"))
        (mkvec (list 1 2 3))
        (mkvec (list 1 2 3)))
      {}))
  (list 3 3))

(apl-test
  "eval-ast inner +.× — dot product"
  (mkrv
    (apl-eval-ast
      (mkdyd
        (mkdr2 "." (mkfg "+") (mkfg "×"))
        (mkvec (list 1 2 3))
        (mkvec (list 4 5 6)))
      {}))
  (list 32))

(apl-test
  "eval-ast inner ∧.= equal vectors"
  (mkrv
    (apl-eval-ast
      (mkdyd
        (mkdr2 "." (mkfg "∧") (mkfg "="))
        (mkvec (list 1 2 3))
        (mkvec (list 1 2 3)))
      {}))
  (list 1))

(apl-test
  "eval-ast each-dyadic +¨"
  (mkrv
    (apl-eval-ast
      (mkdyd
        (mkder "¨" (mkfg "+"))
        (mkvec (list 1 2 3))
        (mkvec (list 10 20 30)))
      {}))
  (list 11 22 33))

(apl-test
  "eval-ast commute -⍨ (subtract swapped)"
  (mkrv
    (apl-eval-ast
      (mkdyd (mkder "⍨" (mkfg "-")) (mknum 5) (mknum 3))
      {}))
  (list -2))

; ---------- nested operators ----------

(apl-test
  "eval-ast +/¨ — sum of each"
  (mkrv
    (apl-eval-ast
      (mkmon (mkder "/" (mkfg "+")) (mkvec (list 10 20 30)))
      {}))
  (list 60))
