;; Top-level declarations: function clauses, type signatures, data, ;; type, newtype, fixity. Driven by hk-parse-top which produces ;; a (:program DECLS) node. (define hk-prog (fn (&rest decls) (list :program decls))) ;; ── Function clauses & pattern bindings ── (hk-test "simple fun-clause" (hk-parse-top "f x = x + 1") (hk-prog (list :fun-clause "f" (list (list :p-var "x")) (list :op "+" (list :var "x") (list :int 1))))) (hk-test "nullary decl" (hk-parse-top "answer = 42") (hk-prog (list :fun-clause "answer" (list) (list :int 42)))) (hk-test "multi-clause fn (separate defs for each pattern)" (hk-parse-top "fact 0 = 1\nfact n = n") (hk-prog (list :fun-clause "fact" (list (list :p-int 0)) (list :int 1)) (list :fun-clause "fact" (list (list :p-var "n")) (list :var "n")))) (hk-test "constructor pattern in fn args" (hk-parse-top "fromJust (Just x) = x") (hk-prog (list :fun-clause "fromJust" (list (list :p-con "Just" (list (list :p-var "x")))) (list :var "x")))) (hk-test "pattern binding at top level" (hk-parse-top "(a, b) = pair") (hk-prog (list :pat-bind (list :p-tuple (list (list :p-var "a") (list :p-var "b"))) (list :var "pair")))) ;; ── Type signatures ── (hk-test "single-name sig" (hk-parse-top "f :: Int -> Int") (hk-prog (list :type-sig (list "f") (list :t-fun (list :t-con "Int") (list :t-con "Int"))))) (hk-test "multi-name sig" (hk-parse-top "f, g, h :: Int -> Bool") (hk-prog (list :type-sig (list "f" "g" "h") (list :t-fun (list :t-con "Int") (list :t-con "Bool"))))) (hk-test "sig with type application" (hk-parse-top "f :: Maybe a -> a") (hk-prog (list :type-sig (list "f") (list :t-fun (list :t-app (list :t-con "Maybe") (list :t-var "a")) (list :t-var "a"))))) (hk-test "sig with list type" (hk-parse-top "len :: [a] -> Int") (hk-prog (list :type-sig (list "len") (list :t-fun (list :t-list (list :t-var "a")) (list :t-con "Int"))))) (hk-test "sig with tuple and right-assoc ->" (hk-parse-top "pair :: a -> b -> (a, b)") (hk-prog (list :type-sig (list "pair") (list :t-fun (list :t-var "a") (list :t-fun (list :t-var "b") (list :t-tuple (list (list :t-var "a") (list :t-var "b")))))))) (hk-test "sig + implementation together" (hk-parse-top "id :: a -> a\nid x = x") (hk-prog (list :type-sig (list "id") (list :t-fun (list :t-var "a") (list :t-var "a"))) (list :fun-clause "id" (list (list :p-var "x")) (list :var "x")))) ;; ── data declarations ── (hk-test "data Maybe" (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 "data Either" (hk-parse-top "data Either a b = Left a | Right b") (hk-prog (list :data "Either" (list "a" "b") (list (list :con-def "Left" (list (list :t-var "a"))) (list :con-def "Right" (list (list :t-var "b"))))))) (hk-test "data with no type parameters" (hk-parse-top "data Bool = True | False") (hk-prog (list :data "Bool" (list) (list (list :con-def "True" (list)) (list :con-def "False" (list)))))) (hk-test "recursive data type" (hk-parse-top "data Tree a = Leaf | Node (Tree a) a (Tree a)") (hk-prog (list :data "Tree" (list "a") (list (list :con-def "Leaf" (list)) (list :con-def "Node" (list (list :t-app (list :t-con "Tree") (list :t-var "a")) (list :t-var "a") (list :t-app (list :t-con "Tree") (list :t-var "a")))))))) ;; ── type synonyms ── (hk-test "simple type synonym" (hk-parse-top "type Name = String") (hk-prog (list :type-syn "Name" (list) (list :t-con "String")))) (hk-test "parameterised type synonym" (hk-parse-top "type Pair a = (a, a)") (hk-prog (list :type-syn "Pair" (list "a") (list :t-tuple (list (list :t-var "a") (list :t-var "a")))))) ;; ── newtype ── (hk-test "newtype" (hk-parse-top "newtype Age = Age Int") (hk-prog (list :newtype "Age" (list) "Age" (list :t-con "Int")))) (hk-test "parameterised newtype" (hk-parse-top "newtype Wrap a = Wrap a") (hk-prog (list :newtype "Wrap" (list "a") "Wrap" (list :t-var "a")))) ;; ── fixity declarations ── (hk-test "infixl with precedence" (hk-parse-top "infixl 5 +:, -:") (hk-prog (list :fixity "l" 5 (list "+:" "-:")))) (hk-test "infixr" (hk-parse-top "infixr 9 .") (hk-prog (list :fixity "r" 9 (list ".")))) (hk-test "infix (non-assoc) default prec" (hk-parse-top "infix ==") (hk-prog (list :fixity "n" 9 (list "==")))) (hk-test "fixity with backtick operator name" (hk-parse-top "infixl 7 `div`") (hk-prog (list :fixity "l" 7 (list "div")))) ;; ── Several decls combined ── (hk-test "mixed: data + sig + fn + type" (hk-parse-top "data Maybe a = Nothing | Just a\ntype Entry = Maybe Int\nf :: Entry -> Int\nf (Just x) = x\nf Nothing = 0") (hk-prog (list :data "Maybe" (list "a") (list (list :con-def "Nothing" (list)) (list :con-def "Just" (list (list :t-var "a"))))) (list :type-syn "Entry" (list) (list :t-app (list :t-con "Maybe") (list :t-con "Int"))) (list :type-sig (list "f") (list :t-fun (list :t-con "Entry") (list :t-con "Int"))) (list :fun-clause "f" (list (list :p-con "Just" (list (list :p-var "x")))) (list :var "x")) (list :fun-clause "f" (list (list :p-con "Nothing" (list))) (list :int 0)))) {:fails hk-test-fails :pass hk-test-pass :fail hk-test-fail}