Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Has been cancelled
257 lines
5.1 KiB
Plaintext
257 lines
5.1 KiB
Plaintext
;; Pattern-matcher tests. The matcher takes (pat val env) and returns
|
|
;; an extended env dict on success, or `nil` on failure. Constructor
|
|
;; values are tagged lists (con-name first); tuples use the "Tuple"
|
|
;; tag; lists use chained `:` cons with `[]` nil.
|
|
|
|
;; ── Atomic patterns ──
|
|
(hk-test
|
|
"wildcard always matches"
|
|
(hk-match (list :p-wild) 42 (dict))
|
|
(dict))
|
|
|
|
(hk-test
|
|
"var binds value"
|
|
(hk-match (list :p-var "x") 42 (dict))
|
|
{:x 42})
|
|
|
|
(hk-test
|
|
"var preserves prior env"
|
|
(hk-match (list :p-var "y") 7 {:x 1})
|
|
{:x 1 :y 7})
|
|
|
|
(hk-test
|
|
"int literal matches equal"
|
|
(hk-match (list :p-int 5) 5 (dict))
|
|
(dict))
|
|
|
|
(hk-test
|
|
"int literal fails on mismatch"
|
|
(hk-match (list :p-int 5) 6 (dict))
|
|
nil)
|
|
|
|
(hk-test
|
|
"negative int literal matches"
|
|
(hk-match (list :p-int -3) -3 (dict))
|
|
(dict))
|
|
|
|
(hk-test
|
|
"string literal matches"
|
|
(hk-match (list :p-string "hi") "hi" (dict))
|
|
(dict))
|
|
|
|
(hk-test
|
|
"string literal fails"
|
|
(hk-match (list :p-string "hi") "bye" (dict))
|
|
nil)
|
|
|
|
(hk-test
|
|
"char literal matches"
|
|
(hk-match (list :p-char "a") "a" (dict))
|
|
(dict))
|
|
|
|
;; ── Constructor patterns ──
|
|
(hk-test
|
|
"0-arity con matches"
|
|
(hk-match
|
|
(list :p-con "Nothing" (list))
|
|
(hk-mk-con "Nothing" (list))
|
|
(dict))
|
|
(dict))
|
|
|
|
(hk-test
|
|
"1-arity con matches and binds"
|
|
(hk-match
|
|
(list :p-con "Just" (list (list :p-var "y")))
|
|
(hk-mk-con "Just" (list 9))
|
|
(dict))
|
|
{:y 9})
|
|
|
|
(hk-test
|
|
"con name mismatch fails"
|
|
(hk-match
|
|
(list :p-con "Just" (list (list :p-var "y")))
|
|
(hk-mk-con "Nothing" (list))
|
|
(dict))
|
|
nil)
|
|
|
|
(hk-test
|
|
"con arity mismatch fails"
|
|
(hk-match
|
|
(list :p-con "Pair" (list (list :p-var "a") (list :p-var "b")))
|
|
(hk-mk-con "Pair" (list 1))
|
|
(dict))
|
|
nil)
|
|
|
|
(hk-test
|
|
"nested con: Just (Just x)"
|
|
(hk-match
|
|
(list
|
|
:p-con
|
|
"Just"
|
|
(list
|
|
(list
|
|
:p-con
|
|
"Just"
|
|
(list (list :p-var "x")))))
|
|
(hk-mk-con "Just" (list (hk-mk-con "Just" (list 42))))
|
|
(dict))
|
|
{:x 42})
|
|
|
|
;; ── Tuple patterns ──
|
|
(hk-test
|
|
"2-tuple matches and binds"
|
|
(hk-match
|
|
(list
|
|
:p-tuple
|
|
(list (list :p-var "a") (list :p-var "b")))
|
|
(hk-mk-tuple (list 10 20))
|
|
(dict))
|
|
{:a 10 :b 20})
|
|
|
|
(hk-test
|
|
"tuple arity mismatch fails"
|
|
(hk-match
|
|
(list
|
|
:p-tuple
|
|
(list (list :p-var "a") (list :p-var "b")))
|
|
(hk-mk-tuple (list 10 20 30))
|
|
(dict))
|
|
nil)
|
|
|
|
;; ── List patterns ──
|
|
(hk-test
|
|
"[] pattern matches empty list"
|
|
(hk-match (list :p-list (list)) (hk-mk-nil) (dict))
|
|
(dict))
|
|
|
|
(hk-test
|
|
"[] pattern fails on non-empty"
|
|
(hk-match (list :p-list (list)) (hk-mk-list (list 1)) (dict))
|
|
nil)
|
|
|
|
(hk-test
|
|
"[a] pattern matches singleton"
|
|
(hk-match
|
|
(list :p-list (list (list :p-var "a")))
|
|
(hk-mk-list (list 7))
|
|
(dict))
|
|
{:a 7})
|
|
|
|
(hk-test
|
|
"[a, b] pattern matches pair-list and binds"
|
|
(hk-match
|
|
(list
|
|
:p-list
|
|
(list (list :p-var "a") (list :p-var "b")))
|
|
(hk-mk-list (list 1 2))
|
|
(dict))
|
|
{:a 1 :b 2})
|
|
|
|
(hk-test
|
|
"[a, b] fails on too-long list"
|
|
(hk-match
|
|
(list
|
|
:p-list
|
|
(list (list :p-var "a") (list :p-var "b")))
|
|
(hk-mk-list (list 1 2 3))
|
|
(dict))
|
|
nil)
|
|
|
|
;; Cons-style infix pattern (which the parser produces as :p-con ":")
|
|
(hk-test
|
|
"cons (h:t) on non-empty list"
|
|
(hk-match
|
|
(list
|
|
:p-con
|
|
":"
|
|
(list (list :p-var "h") (list :p-var "t")))
|
|
(hk-mk-list (list 1 2 3))
|
|
(dict))
|
|
{:h 1 :t (list ":" 2 (list ":" 3 (list "[]")))})
|
|
|
|
(hk-test
|
|
"cons fails on empty list"
|
|
(hk-match
|
|
(list
|
|
:p-con
|
|
":"
|
|
(list (list :p-var "h") (list :p-var "t")))
|
|
(hk-mk-nil)
|
|
(dict))
|
|
nil)
|
|
|
|
;; ── as patterns ──
|
|
(hk-test
|
|
"as binds whole + sub-pattern"
|
|
(hk-match
|
|
(list
|
|
:p-as
|
|
"all"
|
|
(list :p-con "Just" (list (list :p-var "x"))))
|
|
(hk-mk-con "Just" (list 99))
|
|
(dict))
|
|
{:all (list "Just" 99) :x 99})
|
|
|
|
(hk-test
|
|
"as on wildcard binds whole"
|
|
(hk-match
|
|
(list :p-as "v" (list :p-wild))
|
|
"anything"
|
|
(dict))
|
|
{:v "anything"})
|
|
|
|
(hk-test
|
|
"as fails when sub-pattern fails"
|
|
(hk-match
|
|
(list
|
|
:p-as
|
|
"n"
|
|
(list :p-con "Just" (list (list :p-var "x"))))
|
|
(hk-mk-con "Nothing" (list))
|
|
(dict))
|
|
nil)
|
|
|
|
;; ── lazy ~ pattern (eager equivalent for now) ──
|
|
(hk-test
|
|
"lazy pattern eager-matches its inner"
|
|
(hk-match
|
|
(list :p-lazy (list :p-var "y"))
|
|
42
|
|
(dict))
|
|
{:y 42})
|
|
|
|
;; ── Source-driven: parse a real Haskell pattern, match a value ──
|
|
(hk-test
|
|
"parsed pattern: Just x against Just 5"
|
|
(hk-match
|
|
(hk-parse-pat-source "Just x")
|
|
(hk-mk-con "Just" (list 5))
|
|
(dict))
|
|
{:x 5})
|
|
|
|
(hk-test
|
|
"parsed pattern: x : xs against [10, 20, 30]"
|
|
(hk-match
|
|
(hk-parse-pat-source "x : xs")
|
|
(hk-mk-list (list 10 20 30))
|
|
(dict))
|
|
{:x 10 :xs (list ":" 20 (list ":" 30 (list "[]")))})
|
|
|
|
(hk-test
|
|
"parsed pattern: (a, b) against (1, 2)"
|
|
(hk-match
|
|
(hk-parse-pat-source "(a, b)")
|
|
(hk-mk-tuple (list 1 2))
|
|
(dict))
|
|
{:a 1 :b 2})
|
|
|
|
(hk-test
|
|
"parsed pattern: n@(Just x) against Just 7"
|
|
(hk-match
|
|
(hk-parse-pat-source "n@(Just x)")
|
|
(hk-mk-con "Just" (list 7))
|
|
(dict))
|
|
{:n (list "Just" 7) :x 7})
|
|
|
|
{:fails hk-test-fails :pass hk-test-pass :fail hk-test-fail}
|