HS: contains/matches ignoring case support — 425→426

- Parser: contains/matches with ignoring case modifier
- Compiler: contains-ignore-case? → hs-contains-ignore-case?
- Compiler: matches-ignore-case? → hs-matches-ignore-case?
- Runtime: downcase-based case-insensitive contains/matches

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-13 09:45:57 +00:00
parent c05d8788c7
commit 4cac08d56f
7 changed files with 72 additions and 20 deletions

View File

@@ -688,11 +688,21 @@
(quote hs-matches?)
(hs-to-sx (nth ast 1))
(hs-to-sx (nth ast 2))))
((= head (quote matches-ignore-case?))
(list
(quote hs-matches-ignore-case?)
(hs-to-sx (nth ast 1))
(hs-to-sx (nth ast 2))))
((= head (quote contains?))
(list
(quote hs-contains?)
(hs-to-sx (nth ast 1))
(hs-to-sx (nth ast 2))))
((= head (quote contains-ignore-case?))
(list
(quote hs-contains-ignore-case?)
(hs-to-sx (nth ast 1))
(hs-to-sx (nth ast 2))))
((= head (quote as))
(list (quote hs-coerce) (hs-to-sx (nth ast 1)) (nth ast 2)))
((= head (quote in?))

View File

@@ -520,9 +520,27 @@
(match-kw "with")
(list (quote ends-with?) left (parse-expr))))
((and (= typ "keyword") (= val "matches"))
(do (adv!) (list (quote matches?) left (parse-expr))))
(do
(adv!)
(let
((right (parse-expr)))
(if
(match-kw "ignoring")
(do
(match-kw "case")
(list (quote matches-ignore-case?) left right))
(list (quote matches?) left right)))))
((and (= typ "keyword") (= val "contains"))
(do (adv!) (list (quote contains?) left (parse-expr))))
(do
(adv!)
(let
((right (parse-expr)))
(if
(match-kw "ignoring")
(do
(match-kw "case")
(list (quote contains-ignore-case?) left right))
(list (quote contains?) left right)))))
((and (= typ "keyword") (= val "as"))
(do
(adv!)

View File

@@ -392,6 +392,12 @@
hs-eq-ignore-case
(fn (a b) (= (downcase (str a)) (downcase (str b)))))
;; DOM query stub — sandbox returns empty list
(define
hs-contains-ignore-case?
(fn
(haystack needle)
(contains? (downcase (str haystack)) (downcase (str needle)))))
;; Method dispatch — obj.method(args)
(define
hs-falsy?
(fn
@@ -403,7 +409,9 @@
((and (list? v) (= (len v) 0)) true)
((= v 0) true)
(true false))))
;; Method dispatch — obj.method(args)
;; ── 0.9.90 features ─────────────────────────────────────────────
;; beep! — debug logging, returns value unchanged
(define
hs-matches?
(fn
@@ -412,9 +420,7 @@
(string? target)
(if (= pattern ".*") true (string-contains? target pattern))
false)))
;; ── 0.9.90 features ─────────────────────────────────────────────
;; beep! — debug logging, returns value unchanged
;; Property-based is — check obj.key truthiness
(define
hs-contains?
(fn
@@ -434,9 +440,9 @@
true
(hs-contains? (rest collection) item)))))
(true false))))
;; Property-based is — check obj.key truthiness
(define precedes? (fn (a b) (< (str a) (str b))))
;; Array slicing (inclusive both ends)
(define precedes? (fn (a b) (< (str a) (str b))))
;; Collection: sorted by
(define
hs-empty?
(fn
@@ -447,7 +453,7 @@
((list? v) (= (len v) 0))
((dict? v) (= (len (keys v)) 0))
(true false))))
;; Collection: sorted by
;; Collection: sorted by descending
(define
hs-empty-target!
(fn
@@ -468,11 +474,11 @@
(dom-set-prop target "value" ""))))
((= tag "FORM") (dom-set-inner-html target ""))
(true (dom-set-inner-html target ""))))))))
;; Collection: sorted by descending
(define hs-first (fn (lst) (first lst)))
;; Collection: split by
(define hs-last (fn (lst) (last lst)))
(define hs-first (fn (lst) (first lst)))
;; Collection: joined by
(define hs-last (fn (lst) (last lst)))
(define
hs-template
(fn