Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Has been cancelled
200 lines
6.4 KiB
Plaintext
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}
|