Files
rose-ash/lib/haskell/tests/parse.sx
giles c07ff90f6b
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Has been cancelled
haskell: layout rule per §10.3 (+15 tests, 58/58)
2026-04-24 17:05:35 +00:00

200 lines
6.4 KiB
Plaintext

;; Haskell parser / tokenizer tests.
;;
;; Lightweight runner: each test checks actual vs expected with
;; structural (deep) equality and accumulates pass/fail counters.
;; Final value of this file is a summary dict with :pass :fail :fails.
;; The hk-test / hk-deep=? helpers live in lib/haskell/testlib.sx
;; and are preloaded by lib/haskell/test.sh.
;; Convenience: tokenize and drop newline + eof tokens so tests focus
;; on meaningful content. Returns list of {:type :value} pairs.
(define
hk-toks
(fn
(src)
(map
(fn (tok) {:value (get tok "value") :type (get tok "type")})
(filter
(fn
(tok)
(let
((ty (get tok "type")))
(not (or (= ty "newline") (= ty "eof")))))
(hk-tokenize src)))))
;; ── 1. Identifiers & reserved words ──
(hk-test "varid simple" (hk-toks "foo") (list {:value "foo" :type "varid"}))
(hk-test
"varid with digits and prime"
(hk-toks "foo123' bar2")
(list {:value "foo123'" :type "varid"} {:value "bar2" :type "varid"}))
(hk-test "conid" (hk-toks "Maybe") (list {:value "Maybe" :type "conid"}))
(hk-test "reserved: where" (hk-toks "where") (list {:value "where" :type "reserved"}))
(hk-test
"reserved: case of"
(hk-toks "case of")
(list {:value "case" :type "reserved"} {:value "of" :type "reserved"}))
(hk-test "underscore is reserved" (hk-toks "_") (list {:value "_" :type "reserved"}))
;; ── 2. Qualified names ──
(hk-test "qvarid" (hk-toks "Data.Map.lookup") (list {:value "Data.Map.lookup" :type "qvarid"}))
(hk-test "qconid" (hk-toks "Data.Map") (list {:value "Data.Map" :type "qconid"}))
(hk-test "qualified operator" (hk-toks "Prelude.+") (list {:value "Prelude.+" :type "varsym"}))
;; ── 3. Numbers ──
(hk-test "integer" (hk-toks "42") (list {:value 42 :type "integer"}))
(hk-test "hex" (hk-toks "0x2A") (list {:value 42 :type "integer"}))
(hk-test "octal" (hk-toks "0o17") (list {:value 15 :type "integer"}))
(hk-test "float" (hk-toks "3.14") (list {:value 3.14 :type "float"}))
(hk-test "float with exp" (hk-toks "1.5e-3") (list {:value 0.0015 :type "float"}))
;; ── 4. Strings / chars ──
(hk-test "string" (hk-toks "\"hello\"") (list {:value "hello" :type "string"}))
(hk-test "char" (hk-toks "'a'") (list {:value "a" :type "char"}))
(hk-test "char escape newline" (hk-toks "'\\n'") (list {:value "\n" :type "char"}))
(hk-test "string escape" (hk-toks "\"a\\nb\"") (list {:value "a\nb" :type "string"}))
;; ── 5. Operators ──
(hk-test "operator +" (hk-toks "+") (list {:value "+" :type "varsym"}))
(hk-test "operator >>=" (hk-toks ">>=") (list {:value ">>=" :type "varsym"}))
(hk-test "consym" (hk-toks ":+:") (list {:value ":+:" :type "consym"}))
(hk-test "reservedop ->" (hk-toks "->") (list {:value "->" :type "reservedop"}))
(hk-test "reservedop =>" (hk-toks "=>") (list {:value "=>" :type "reservedop"}))
(hk-test "reservedop .. (range)" (hk-toks "..") (list {:value ".." :type "reservedop"}))
(hk-test "reservedop backslash" (hk-toks "\\") (list {:value "\\" :type "reservedop"}))
;; ── 6. Punctuation ──
(hk-test "parens" (hk-toks "( )") (list {:value "(" :type "lparen"} {:value ")" :type "rparen"}))
(hk-test "brackets" (hk-toks "[]") (list {:value "[" :type "lbracket"} {:value "]" :type "rbracket"}))
(hk-test "braces" (hk-toks "{}") (list {:value "{" :type "lbrace"} {:value "}" :type "rbrace"}))
(hk-test
"backtick"
(hk-toks "`mod`")
(list {:value "`" :type "backtick"} {:value "mod" :type "varid"} {:value "`" :type "backtick"}))
(hk-test "comma and semi" (hk-toks ",;") (list {:value "," :type "comma"} {:value ";" :type "semi"}))
;; ── 7. Comments ──
(hk-test "line comment stripped" (hk-toks "-- a comment") (list))
(hk-test "line comment before code" (hk-toks "-- c\nfoo") (list {:value "foo" :type "varid"}))
(hk-test
"block comment stripped"
(hk-toks "{- block -} foo")
(list {:value "foo" :type "varid"}))
(hk-test
"nested block comment"
(hk-toks "{- {- nested -} -} x")
(list {:value "x" :type "varid"}))
(hk-test
"-- inside operator is comment in Haskell"
(hk-toks "-->")
(list {:value "-->" :type "varsym"}))
;; ── 8. Mixed declarations ──
(hk-test
"type signature"
(hk-toks "main :: IO ()")
(list {:value "main" :type "varid"} {:value "::" :type "reservedop"} {:value "IO" :type "conid"} {:value "(" :type "lparen"} {:value ")" :type "rparen"}))
(hk-test
"data declaration"
(hk-toks "data Maybe a = Nothing | Just a")
(list
{:value "data" :type "reserved"}
{:value "Maybe" :type "conid"}
{:value "a" :type "varid"}
{:value "=" :type "reservedop"}
{:value "Nothing" :type "conid"}
{:value "|" :type "reservedop"}
{:value "Just" :type "conid"}
{:value "a" :type "varid"}))
(hk-test
"lambda"
(hk-toks "\\x -> x + 1")
(list {:value "\\" :type "reservedop"} {:value "x" :type "varid"} {:value "->" :type "reservedop"} {:value "x" :type "varid"} {:value "+" :type "varsym"} {:value 1 :type "integer"}))
(hk-test
"let expression"
(hk-toks "let x = 1 in x + x")
(list
{:value "let" :type "reserved"}
{:value "x" :type "varid"}
{:value "=" :type "reservedop"}
{:value 1 :type "integer"}
{:value "in" :type "reserved"}
{:value "x" :type "varid"}
{:value "+" :type "varsym"}
{:value "x" :type "varid"}))
(hk-test
"case expr"
(hk-toks "case x of Just y -> y")
(list
{:value "case" :type "reserved"}
{:value "x" :type "varid"}
{:value "of" :type "reserved"}
{:value "Just" :type "conid"}
{:value "y" :type "varid"}
{:value "->" :type "reservedop"}
{:value "y" :type "varid"}))
(hk-test
"list literal"
(hk-toks "[1, 2, 3]")
(list
{:value "[" :type "lbracket"}
{:value 1 :type "integer"}
{:value "," :type "comma"}
{:value 2 :type "integer"}
{:value "," :type "comma"}
{:value 3 :type "integer"}
{:value "]" :type "rbracket"}))
(hk-test
"range syntax"
(hk-toks "[1..10]")
(list {:value "[" :type "lbracket"} {:value 1 :type "integer"} {:value ".." :type "reservedop"} {:value 10 :type "integer"} {:value "]" :type "rbracket"}))
;; ── 9. Positions ──
(hk-test
"line/col positions"
(let
((toks (hk-tokenize "foo\n bar")))
(list
(get (nth toks 0) "line")
(get (nth toks 0) "col")
(get (nth toks 2) "line")
(get (nth toks 2) "col")))
(list 1 1 2 3))
;; ── Summary — final value of this file ──
{:fails hk-test-fails :pass hk-test-pass :fail hk-test-fail}