;; String / Char tests — Phase 7 items 1-4. ;; ;; Covers: ;; hk-str? / hk-str-head / hk-str-tail / hk-str-null? (runtime helpers) ;; chr / ord / toUpper / toLower (builtins in eval) ;; cons-pattern on strings via match.sx (":"-intercept) ;; empty-list pattern on strings via match.sx ("[]"-intercept) ;; ── hk-str? predicate ──────────────────────────────────────────────────── (hk-test "hk-str? native string" (hk-str? "hello") true) (hk-test "hk-str? empty string" (hk-str? "") true) (hk-test "hk-str? view dict" (hk-str? {:hk-off 1 :hk-str "hi"}) true) (hk-test "hk-str? rejects number" (hk-str? 42) false) ;; ── hk-str-null? predicate ─────────────────────────────────────────────── (hk-test "hk-str-null? empty string" (hk-str-null? "") true) (hk-test "hk-str-null? non-empty" (hk-str-null? "a") false) (hk-test "hk-str-null? exhausted view" (hk-str-null? {:hk-off 2 :hk-str "hi"}) true) (hk-test "hk-str-null? live view" (hk-str-null? {:hk-off 1 :hk-str "hi"}) false) ;; ── hk-str-head ────────────────────────────────────────────────────────── (hk-test "hk-str-head native string" (hk-str-head "hello") 104) (hk-test "hk-str-head view at offset" (hk-str-head {:hk-off 1 :hk-str "hello"}) 101) ;; ── hk-str-tail ────────────────────────────────────────────────────────── (hk-test "hk-str-tail of single char is nil" (hk-str-tail "h") (list "[]")) (hk-test "hk-str-tail of two-char string is live view" (hk-str-null? (hk-str-tail "hi")) false) (hk-test "hk-str-tail head of tail of hi is i" (hk-str-head (hk-str-tail "hi")) 105) ;; ── chr / ord ──────────────────────────────────────────────────────────── (hk-test "chr 65 = A" (hk-eval-expr-source "chr 65") "A") (hk-test "chr 104 = h" (hk-eval-expr-source "chr 104") "h") (hk-test "ord char literal 'A' = 65" (hk-eval-expr-source "ord 'A'") 65) (hk-test "ord char literal 'a' = 97" (hk-eval-expr-source "ord 'a'") 97) (hk-test "ord of head string = char code" (hk-eval-expr-source "ord (head \"hello\")") 104) ;; ── toUpper / toLower ──────────────────────────────────────────────────── (hk-test "toUpper 97 = 65 (a->A)" (hk-eval-expr-source "toUpper 97") 65) (hk-test "toUpper 65 = 65 (already upper)" (hk-eval-expr-source "toUpper 65") 65) (hk-test "toUpper 48 = 48 (digit unchanged)" (hk-eval-expr-source "toUpper 48") 48) (hk-test "toLower 65 = 97 (A->a)" (hk-eval-expr-source "toLower 65") 97) (hk-test "toLower 97 = 97 (already lower)" (hk-eval-expr-source "toLower 97") 97) (hk-test "toLower 48 = 48 (digit unchanged)" (hk-eval-expr-source "toLower 48") 48) ;; ── Pattern matching on strings ────────────────────────────────────────── (hk-test "cons pattern: head of hello = 104" (hk-eval-expr-source "case \"hello\" of { (x:_) -> x }") 104) (hk-test "cons pattern: tail is traversable" (hk-eval-expr-source "case \"hi\" of { (_:xs) -> case xs of { (y:_) -> y } }") 105) (hk-test "empty list pattern matches empty string" (hk-eval-expr-source "case \"\" of { [] -> True; _ -> False }") (list "True")) (hk-test "empty list pattern fails on non-empty" (hk-eval-expr-source "case \"a\" of { [] -> True; _ -> False }") (list "False")) (hk-test "cons pattern fails on empty string" (hk-eval-expr-source "case \"\" of { (_:_) -> True; _ -> False }") (list "False")) ;; ── Haskell programs using string traversal ────────────────────────────── (hk-test "null prelude on empty string" (hk-eval-expr-source "null \"\"") (list "True")) (hk-test "null prelude on non-empty string" (hk-eval-expr-source "null \"abc\"") (list "False")) (hk-test "length of string via cons recursion" (hk-eval-expr-source "let { f [] = 0; f (_:xs) = 1 + f xs } in f \"hello\"") 5) (hk-test "map ord over string gives char codes" (hk-deep-force (hk-eval-expr-source "map ord \"abc\"")) (list ":" 97 (list ":" 98 (list ":" 99 (list "[]"))))) (hk-test "map toUpper over char codes then chr" (hk-eval-expr-source "chr (toUpper (ord (head \"abc\")))") "A") (hk-test "head then ord using prelude head" (hk-eval-expr-source "ord (head \"hello\")") 104)