HS: in-expression filter semantics (+1 test)

`1 in [1, 2, 3]` must return (list 1) not true. Root cause: in? compiled
to hs-contains? which returns boolean for scalar items. Fix: new hs-in?
returns filtered list; new in-bool? operator for is/am-in comparison
contexts so those still return boolean. Parser generates in-bool? for
`X is in Y` / `X am in Y`; plain `in` keeps in? → list return.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-25 18:35:26 +00:00
parent db8d7aca91
commit 67a5f13713
6 changed files with 112 additions and 20 deletions

View File

@@ -1059,9 +1059,16 @@
(quote hs-method-call)
(cons obj (cons method args))))
(if
(and (list? dot-node) (= (first dot-node) (quote ref)))
(list (quote hs-win-call) (nth dot-node 1) (cons (quote list) args))
(cons (quote hs-method-call) (cons (hs-to-sx dot-node) args))))))
(and
(list? dot-node)
(= (first dot-node) (quote ref)))
(list
(quote hs-win-call)
(nth dot-node 1)
(cons (quote list) args))
(cons
(quote hs-method-call)
(cons (hs-to-sx dot-node) args))))))
((= head (quote string-postfix))
(list (quote str) (hs-to-sx (nth ast 1)) (nth ast 2)))
((= head (quote block-literal))
@@ -1231,7 +1238,12 @@
(list (quote hs-coerce) (hs-to-sx (nth ast 1)) (nth ast 2)))
((= head (quote in?))
(list
(quote hs-contains?)
(quote hs-in?)
(hs-to-sx (nth ast 2))
(hs-to-sx (nth ast 1))))
((= head (quote in-bool?))
(list
(quote hs-in-bool?)
(hs-to-sx (nth ast 2))
(hs-to-sx (nth ast 1))))
((= head (quote of))
@@ -1717,7 +1729,16 @@
(rest (reverse compiled)))
(let
((defs (filter (fn (c) (and (list? c) (> (len c) 0) (= (first c) (quote define)))) compiled))
(non-defs (filter (fn (c) (not (and (list? c) (> (len c) 0) (= (first c) (quote define))))) compiled)))
(non-defs
(filter
(fn
(c)
(not
(and
(list? c)
(> (len c) 0)
(= (first c) (quote define)))))
compiled)))
(cons (quote do) (append defs non-defs)))))))
((= head (quote wait)) (list (quote hs-wait) (nth ast 1)))
((= head (quote wait-for)) (emit-wait-for ast))
@@ -1826,8 +1847,12 @@
(make-symbol raw-fn)
(hs-to-sx raw-fn)))
(args (map hs-to-sx (rest (rest ast)))))
(if (and (list? raw-fn) (= (first raw-fn) (quote ref)))
(list (quote hs-win-call) (nth raw-fn 1) (cons (quote list) args))
(if
(and (list? raw-fn) (= (first raw-fn) (quote ref)))
(list
(quote hs-win-call)
(nth raw-fn 1)
(cons (quote list) args))
(cons fn-expr args))))
((= head (quote return))
(let
@@ -2098,7 +2123,7 @@
(hs-to-sx (nth ast 1)))))
((= head (quote in?))
(list
(quote hs-contains?)
(quote hs-in?)
(hs-to-sx (nth ast 2))
(hs-to-sx (nth ast 1))))
((= head (quote type-check))

View File

@@ -495,7 +495,8 @@
(quote and)
(list (quote >=) left lo)
(list (quote <=) left hi)))))
((match-kw "in") (list (quote in?) left (parse-expr)))
((match-kw "in")
(list (quote in-bool?) left (parse-expr)))
((match-kw "really")
(do
(match-kw "equal")
@@ -571,7 +572,8 @@
(let
((right (parse-expr)))
(list (quote not) (list (quote =) left right))))))
((match-kw "in") (list (quote in?) left (parse-expr)))
((match-kw "in")
(list (quote in-bool?) left (parse-expr)))
((match-kw "empty") (list (quote empty?) left))
((match-kw "between")
(let

View File

@@ -1535,6 +1535,25 @@
(hs-contains? (rest collection) item))))))
(true false))))
(define
hs-in?
(fn
(collection item)
(cond
((nil? collection) (list))
((list? collection)
(cond
((nil? item) (list))
((list? item)
(filter (fn (x) (hs-contains? collection x)) item))
((hs-contains? collection item) (list item))
(true (list))))
(true (list)))))
(define
hs-in-bool?
(fn (collection item) (not (hs-falsy? (hs-in? collection item)))))
(define
hs-is
(fn

View File

@@ -1059,9 +1059,16 @@
(quote hs-method-call)
(cons obj (cons method args))))
(if
(and (list? dot-node) (= (first dot-node) (quote ref)))
(list (quote hs-win-call) (nth dot-node 1) (cons (quote list) args))
(cons (quote hs-method-call) (cons (hs-to-sx dot-node) args))))))
(and
(list? dot-node)
(= (first dot-node) (quote ref)))
(list
(quote hs-win-call)
(nth dot-node 1)
(cons (quote list) args))
(cons
(quote hs-method-call)
(cons (hs-to-sx dot-node) args))))))
((= head (quote string-postfix))
(list (quote str) (hs-to-sx (nth ast 1)) (nth ast 2)))
((= head (quote block-literal))
@@ -1231,7 +1238,12 @@
(list (quote hs-coerce) (hs-to-sx (nth ast 1)) (nth ast 2)))
((= head (quote in?))
(list
(quote hs-contains?)
(quote hs-in?)
(hs-to-sx (nth ast 2))
(hs-to-sx (nth ast 1))))
((= head (quote in-bool?))
(list
(quote hs-in-bool?)
(hs-to-sx (nth ast 2))
(hs-to-sx (nth ast 1))))
((= head (quote of))
@@ -1717,7 +1729,16 @@
(rest (reverse compiled)))
(let
((defs (filter (fn (c) (and (list? c) (> (len c) 0) (= (first c) (quote define)))) compiled))
(non-defs (filter (fn (c) (not (and (list? c) (> (len c) 0) (= (first c) (quote define))))) compiled)))
(non-defs
(filter
(fn
(c)
(not
(and
(list? c)
(> (len c) 0)
(= (first c) (quote define)))))
compiled)))
(cons (quote do) (append defs non-defs)))))))
((= head (quote wait)) (list (quote hs-wait) (nth ast 1)))
((= head (quote wait-for)) (emit-wait-for ast))
@@ -1826,8 +1847,12 @@
(make-symbol raw-fn)
(hs-to-sx raw-fn)))
(args (map hs-to-sx (rest (rest ast)))))
(if (and (list? raw-fn) (= (first raw-fn) (quote ref)))
(list (quote hs-win-call) (nth raw-fn 1) (cons (quote list) args))
(if
(and (list? raw-fn) (= (first raw-fn) (quote ref)))
(list
(quote hs-win-call)
(nth raw-fn 1)
(cons (quote list) args))
(cons fn-expr args))))
((= head (quote return))
(let
@@ -2098,7 +2123,7 @@
(hs-to-sx (nth ast 1)))))
((= head (quote in?))
(list
(quote hs-contains?)
(quote hs-in?)
(hs-to-sx (nth ast 2))
(hs-to-sx (nth ast 1))))
((= head (quote type-check))

View File

@@ -495,7 +495,8 @@
(quote and)
(list (quote >=) left lo)
(list (quote <=) left hi)))))
((match-kw "in") (list (quote in?) left (parse-expr)))
((match-kw "in")
(list (quote in-bool?) left (parse-expr)))
((match-kw "really")
(do
(match-kw "equal")
@@ -571,7 +572,8 @@
(let
((right (parse-expr)))
(list (quote not) (list (quote =) left right))))))
((match-kw "in") (list (quote in?) left (parse-expr)))
((match-kw "in")
(list (quote in-bool?) left (parse-expr)))
((match-kw "empty") (list (quote empty?) left))
((match-kw "between")
(let

View File

@@ -1535,6 +1535,25 @@
(hs-contains? (rest collection) item))))))
(true false))))
(define
hs-in?
(fn
(collection item)
(cond
((nil? collection) (list))
((list? collection)
(cond
((nil? item) (list))
((list? item)
(filter (fn (x) (hs-contains? collection x)) item))
((hs-contains? collection item) (list item))
(true (list))))
(true (list)))))
(define
hs-in-bool?
(fn (collection item) (not (hs-falsy? (hs-in? collection item)))))
(define
hs-is
(fn