Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Has been cancelled
259 lines
5.9 KiB
Plaintext
259 lines
5.9 KiB
Plaintext
;; Haskell expression parser tests.
|
|
;; hk-parse tokenises, runs layout, then parses. Output is an AST
|
|
;; whose head is a keyword tag (evaluates to its string name).
|
|
|
|
;; ── 1. Literals ──
|
|
(hk-test "integer" (hk-parse "42") (list :int 42))
|
|
(hk-test "float" (hk-parse "3.14") (list :float 3.14))
|
|
(hk-test "string" (hk-parse "\"hi\"") (list :string "hi"))
|
|
(hk-test "char" (hk-parse "'a'") (list :char "a"))
|
|
|
|
;; ── 2. Variables and constructors ──
|
|
(hk-test "varid" (hk-parse "foo") (list :var "foo"))
|
|
(hk-test "conid" (hk-parse "Nothing") (list :con "Nothing"))
|
|
(hk-test "qvarid" (hk-parse "Data.Map.lookup") (list :var "Data.Map.lookup"))
|
|
(hk-test "qconid" (hk-parse "Data.Map") (list :con "Data.Map"))
|
|
|
|
;; ── 3. Parens / unit / tuple ──
|
|
(hk-test "parens strip" (hk-parse "(42)") (list :int 42))
|
|
(hk-test "unit" (hk-parse "()") (list :con "()"))
|
|
(hk-test
|
|
"2-tuple"
|
|
(hk-parse "(1, 2)")
|
|
(list :tuple (list (list :int 1) (list :int 2))))
|
|
(hk-test
|
|
"3-tuple"
|
|
(hk-parse "(x, y, z)")
|
|
(list
|
|
:tuple
|
|
(list (list :var "x") (list :var "y") (list :var "z"))))
|
|
|
|
;; ── 4. Lists ──
|
|
(hk-test "empty list" (hk-parse "[]") (list :list (list)))
|
|
(hk-test
|
|
"singleton list"
|
|
(hk-parse "[1]")
|
|
(list :list (list (list :int 1))))
|
|
(hk-test
|
|
"list of ints"
|
|
(hk-parse "[1, 2, 3]")
|
|
(list
|
|
:list
|
|
(list (list :int 1) (list :int 2) (list :int 3))))
|
|
(hk-test
|
|
"range"
|
|
(hk-parse "[1..10]")
|
|
(list :range (list :int 1) (list :int 10)))
|
|
(hk-test
|
|
"range with step"
|
|
(hk-parse "[1, 3..10]")
|
|
(list
|
|
:range-step
|
|
(list :int 1)
|
|
(list :int 3)
|
|
(list :int 10)))
|
|
|
|
;; ── 5. Application ──
|
|
(hk-test
|
|
"one-arg app"
|
|
(hk-parse "f x")
|
|
(list :app (list :var "f") (list :var "x")))
|
|
(hk-test
|
|
"multi-arg app is left-assoc"
|
|
(hk-parse "f x y z")
|
|
(list
|
|
:app
|
|
(list
|
|
:app
|
|
(list :app (list :var "f") (list :var "x"))
|
|
(list :var "y"))
|
|
(list :var "z")))
|
|
(hk-test
|
|
"app with con"
|
|
(hk-parse "Just 5")
|
|
(list :app (list :con "Just") (list :int 5)))
|
|
|
|
;; ── 6. Infix operators ──
|
|
(hk-test
|
|
"simple +"
|
|
(hk-parse "1 + 2")
|
|
(list :op "+" (list :int 1) (list :int 2)))
|
|
(hk-test
|
|
"precedence: * binds tighter than +"
|
|
(hk-parse "1 + 2 * 3")
|
|
(list
|
|
:op
|
|
"+"
|
|
(list :int 1)
|
|
(list :op "*" (list :int 2) (list :int 3))))
|
|
(hk-test
|
|
"- is left-assoc"
|
|
(hk-parse "10 - 3 - 2")
|
|
(list
|
|
:op
|
|
"-"
|
|
(list :op "-" (list :int 10) (list :int 3))
|
|
(list :int 2)))
|
|
(hk-test
|
|
": is right-assoc"
|
|
(hk-parse "a : b : c")
|
|
(list
|
|
:op
|
|
":"
|
|
(list :var "a")
|
|
(list :op ":" (list :var "b") (list :var "c"))))
|
|
(hk-test
|
|
"app binds tighter than op"
|
|
(hk-parse "f x + g y")
|
|
(list
|
|
:op
|
|
"+"
|
|
(list :app (list :var "f") (list :var "x"))
|
|
(list :app (list :var "g") (list :var "y"))))
|
|
(hk-test
|
|
"$ is lowest precedence, right-assoc"
|
|
(hk-parse "f $ g x")
|
|
(list
|
|
:op
|
|
"$"
|
|
(list :var "f")
|
|
(list :app (list :var "g") (list :var "x"))))
|
|
|
|
;; ── 7. Backticks (varid-as-operator) ──
|
|
(hk-test
|
|
"backtick operator"
|
|
(hk-parse "x `mod` 3")
|
|
(list :op "mod" (list :var "x") (list :int 3)))
|
|
|
|
;; ── 8. Unary negation ──
|
|
(hk-test
|
|
"unary -"
|
|
(hk-parse "- 5")
|
|
(list :neg (list :int 5)))
|
|
(hk-test
|
|
"unary - on application"
|
|
(hk-parse "- f x")
|
|
(list :neg (list :app (list :var "f") (list :var "x"))))
|
|
(hk-test
|
|
"- n + m → (- n) + m"
|
|
(hk-parse "- 1 + 2")
|
|
(list
|
|
:op
|
|
"+"
|
|
(list :neg (list :int 1))
|
|
(list :int 2)))
|
|
|
|
;; ── 9. Lambda ──
|
|
(hk-test
|
|
"lambda single param"
|
|
(hk-parse "\\x -> x")
|
|
(list :lambda (list "x") (list :var "x")))
|
|
(hk-test
|
|
"lambda multi-param"
|
|
(hk-parse "\\x y -> x + y")
|
|
(list
|
|
:lambda
|
|
(list "x" "y")
|
|
(list :op "+" (list :var "x") (list :var "y"))))
|
|
(hk-test
|
|
"lambda body is full expression"
|
|
(hk-parse "\\f -> f 1 + f 2")
|
|
(list
|
|
:lambda
|
|
(list "f")
|
|
(list
|
|
:op
|
|
"+"
|
|
(list :app (list :var "f") (list :int 1))
|
|
(list :app (list :var "f") (list :int 2)))))
|
|
|
|
;; ── 10. if-then-else ──
|
|
(hk-test
|
|
"if basic"
|
|
(hk-parse "if x then 1 else 2")
|
|
(list :if (list :var "x") (list :int 1) (list :int 2)))
|
|
(hk-test
|
|
"if with infix cond"
|
|
(hk-parse "if x == 0 then y else z")
|
|
(list
|
|
:if
|
|
(list :op "==" (list :var "x") (list :int 0))
|
|
(list :var "y")
|
|
(list :var "z")))
|
|
|
|
;; ── 11. let-in ──
|
|
(hk-test
|
|
"let single binding"
|
|
(hk-parse "let x = 1 in x")
|
|
(list
|
|
:let
|
|
(list (list :bind "x" (list :int 1)))
|
|
(list :var "x")))
|
|
(hk-test
|
|
"let two bindings (multi-line)"
|
|
(hk-parse "let x = 1\n y = 2\nin x + y")
|
|
(list
|
|
:let
|
|
(list
|
|
(list :bind "x" (list :int 1))
|
|
(list :bind "y" (list :int 2)))
|
|
(list :op "+" (list :var "x") (list :var "y"))))
|
|
(hk-test
|
|
"let with explicit braces"
|
|
(hk-parse "let { x = 1 ; y = 2 } in x + y")
|
|
(list
|
|
:let
|
|
(list
|
|
(list :bind "x" (list :int 1))
|
|
(list :bind "y" (list :int 2)))
|
|
(list :op "+" (list :var "x") (list :var "y"))))
|
|
|
|
;; ── 12. Mixed / nesting ──
|
|
(hk-test
|
|
"nested application"
|
|
(hk-parse "f (g x) y")
|
|
(list
|
|
:app
|
|
(list
|
|
:app
|
|
(list :var "f")
|
|
(list :app (list :var "g") (list :var "x")))
|
|
(list :var "y")))
|
|
(hk-test
|
|
"lambda applied"
|
|
(hk-parse "(\\x -> x + 1) 5")
|
|
(list
|
|
:app
|
|
(list
|
|
:lambda
|
|
(list "x")
|
|
(list :op "+" (list :var "x") (list :int 1)))
|
|
(list :int 5)))
|
|
(hk-test
|
|
"lambda + if"
|
|
(hk-parse "\\n -> if n == 0 then 1 else n")
|
|
(list
|
|
:lambda
|
|
(list "n")
|
|
(list
|
|
:if
|
|
(list :op "==" (list :var "n") (list :int 0))
|
|
(list :int 1)
|
|
(list :var "n"))))
|
|
|
|
;; ── 13. Precedence corners ──
|
|
(hk-test
|
|
". is right-assoc (prec 9)"
|
|
(hk-parse "f . g . h")
|
|
(list
|
|
:op
|
|
"."
|
|
(list :var "f")
|
|
(list :op "." (list :var "g") (list :var "h"))))
|
|
(hk-test
|
|
"== is non-associative (single use)"
|
|
(hk-parse "x == y")
|
|
(list :op "==" (list :var "x") (list :var "y")))
|
|
|
|
{:fails hk-test-fails :pass hk-test-pass :fail hk-test-fail}
|