;; Desugar tests — surface AST → core AST.
;;   :guarded   →  nested :if
;;   :where     →  :let
;;   :list-comp →  concatMap-based tree

(define
  hk-prog
  (fn (&rest decls) (list :program decls)))

;; ── Guards → if ──
(hk-test
  "two-way guarded rhs"
  (hk-desugar (hk-parse-top "abs x | x < 0 = - x\n      | otherwise = x"))
  (hk-prog
    (list
      :fun-clause
      "abs"
      (list (list :p-var "x"))
      (list
        :if
        (list :op "<" (list :var "x") (list :int 0))
        (list :neg (list :var "x"))
        (list
          :if
          (list :var "otherwise")
          (list :var "x")
          (list
            :app
            (list :var "error")
            (list :string "Non-exhaustive guards")))))))

(hk-test
  "three-way guarded rhs"
  (hk-desugar
    (hk-parse-top "sign n | n > 0 = 1\n       | n < 0 = -1\n       | otherwise = 0"))
  (hk-prog
    (list
      :fun-clause
      "sign"
      (list (list :p-var "n"))
      (list
        :if
        (list :op ">" (list :var "n") (list :int 0))
        (list :int 1)
        (list
          :if
          (list :op "<" (list :var "n") (list :int 0))
          (list :neg (list :int 1))
          (list
            :if
            (list :var "otherwise")
            (list :int 0)
            (list
              :app
              (list :var "error")
              (list :string "Non-exhaustive guards"))))))))

(hk-test
  "case-alt guards desugared too"
  (hk-desugar
    (hk-parse "case x of\n  Just y | y > 0 -> y\n         | otherwise -> 0\n  Nothing -> -1"))
  (list
    :case
    (list :var "x")
    (list
      (list
        :alt
        (list :p-con "Just" (list (list :p-var "y")))
        (list
          :if
          (list :op ">" (list :var "y") (list :int 0))
          (list :var "y")
          (list
            :if
            (list :var "otherwise")
            (list :int 0)
            (list
              :app
              (list :var "error")
              (list :string "Non-exhaustive guards")))))
      (list
        :alt
        (list :p-con "Nothing" (list))
        (list :neg (list :int 1))))))

;; ── Where → let ──
(hk-test
  "where with single binding"
  (hk-desugar (hk-parse-top "f x = y\n  where y = x + 1"))
  (hk-prog
    (list
      :fun-clause
      "f"
      (list (list :p-var "x"))
      (list
        :let
        (list
          (list
            :fun-clause
            "y"
            (list)
            (list :op "+" (list :var "x") (list :int 1))))
        (list :var "y")))))

(hk-test
  "where with two bindings"
  (hk-desugar
    (hk-parse-top "f x = y + z\n  where y = x + 1\n        z = x - 1"))
  (hk-prog
    (list
      :fun-clause
      "f"
      (list (list :p-var "x"))
      (list
        :let
        (list
          (list
            :fun-clause
            "y"
            (list)
            (list :op "+" (list :var "x") (list :int 1)))
          (list
            :fun-clause
            "z"
            (list)
            (list :op "-" (list :var "x") (list :int 1))))
        (list :op "+" (list :var "y") (list :var "z"))))))

(hk-test
  "guards + where — guarded body inside let"
  (hk-desugar
    (hk-parse-top "f x | x > 0 = y\n    | otherwise = 0\n  where y = 99"))
  (hk-prog
    (list
      :fun-clause
      "f"
      (list (list :p-var "x"))
      (list
        :let
        (list (list :fun-clause "y" (list) (list :int 99)))
        (list
          :if
          (list :op ">" (list :var "x") (list :int 0))
          (list :var "y")
          (list
            :if
            (list :var "otherwise")
            (list :int 0)
            (list
              :app
              (list :var "error")
              (list :string "Non-exhaustive guards"))))))))

;; ── List comprehensions → concatMap / if / let ──
(hk-test
  "list-comp: single generator"
  (hk-core-expr "[x | x <- xs]")
  (list
    :app
    (list
      :app
      (list :var "concatMap")
      (list
        :lambda
        (list (list :p-var "x"))
        (list :list (list (list :var "x")))))
    (list :var "xs")))

(hk-test
  "list-comp: generator then guard"
  (hk-core-expr "[x * 2 | x <- xs, x > 0]")
  (list
    :app
    (list
      :app
      (list :var "concatMap")
      (list
        :lambda
        (list (list :p-var "x"))
        (list
          :if
          (list :op ">" (list :var "x") (list :int 0))
          (list
            :list
            (list (list :op "*" (list :var "x") (list :int 2))))
          (list :list (list)))))
    (list :var "xs")))

(hk-test
  "list-comp: generator then let"
  (hk-core-expr "[y | x <- xs, let y = x + 1]")
  (list
    :app
    (list
      :app
      (list :var "concatMap")
      (list
        :lambda
        (list (list :p-var "x"))
        (list
          :let
          (list
            (list
              :bind
              (list :p-var "y")
              (list :op "+" (list :var "x") (list :int 1))))
          (list :list (list (list :var "y"))))))
    (list :var "xs")))

(hk-test
  "list-comp: two generators (nested concatMap)"
  (hk-core-expr "[(x, y) | x <- xs, y <- ys]")
  (list
    :app
    (list
      :app
      (list :var "concatMap")
      (list
        :lambda
        (list (list :p-var "x"))
        (list
          :app
          (list
            :app
            (list :var "concatMap")
            (list
              :lambda
              (list (list :p-var "y"))
              (list
                :list
                (list
                  (list
                    :tuple
                    (list (list :var "x") (list :var "y")))))))
          (list :var "ys"))))
    (list :var "xs")))

;; ── Pass-through cases ──
(hk-test
  "plain int literal unchanged"
  (hk-core-expr "42")
  (list :int 42))

(hk-test
  "lambda + if passes through"
  (hk-core-expr "\\x -> if x > 0 then x else - x")
  (list
    :lambda
    (list (list :p-var "x"))
    (list
      :if
      (list :op ">" (list :var "x") (list :int 0))
      (list :var "x")
      (list :neg (list :var "x")))))

(hk-test
  "simple fun-clause (no guards/where) passes through"
  (hk-desugar (hk-parse-top "id x = x"))
  (hk-prog
    (list
      :fun-clause
      "id"
      (list (list :p-var "x"))
      (list :var "x"))))

(hk-test
  "data decl passes through"
  (hk-desugar (hk-parse-top "data Maybe a = Nothing | Just a"))
  (hk-prog
    (list
      :data
      "Maybe"
      (list "a")
      (list
        (list :con-def "Nothing" (list))
        (list :con-def "Just" (list (list :t-var "a")))))))

(hk-test
  "module header passes through, body desugared"
  (hk-desugar
    (hk-parse-top "module M where\nf x | x > 0 = 1\n    | otherwise = 0"))
  (list
    :module
    "M"
    nil
    (list)
    (list
      (list
        :fun-clause
        "f"
        (list (list :p-var "x"))
        (list
          :if
          (list :op ">" (list :var "x") (list :int 0))
          (list :int 1)
          (list
            :if
            (list :var "otherwise")
            (list :int 0)
            (list
              :app
              (list :var "error")
              (list :string "Non-exhaustive guards"))))))))

{:fails hk-test-fails :pass hk-test-pass :fail hk-test-fail}
