diff --git a/src/jolt/core.janet b/src/jolt/core.janet index 6762732..b03696a 100644 --- a/src/jolt/core.janet +++ b/src/jolt/core.janet @@ -167,11 +167,27 @@ (defn core-keyword? [x] (keyword? x)) (defn core-symbol? [x] (and (struct? x) (= :symbol (x :jolt/type)))) (defn core-vector? [x] (jvec? x)) -(defn core-map? [x] (or (phm? x) (struct? x) (if (and (table? x) (get x :jolt/deftype)) true false))) +# map? is STRICT: a plain struct map literal, a phm, a sorted map, or a record. +# Tagged structs (symbols/chars/uuids — anything with :jolt/type) are VALUES, +# not maps. (sorted-map? is defined later, so the table check is inlined.) +(defn core-map? [x] + (or (phm? x) + (and (struct? x) (nil? (get x :jolt/type))) + (and (table? x) + (or (not (nil? (get x :jolt/deftype))) + (= :jolt/sorted-map (get x :jolt/type)))))) # seq? is true only for actual sequences (lists, lazy-seqs) — NOT vectors, which # are not ISeq in Clojure. (A Janet array represents a Clojure list/seq result.) (defn core-seq? [x] (or (array? x) (plist? x) (lazy-seq? x))) -(defn core-coll? [x] (or (array? x) (tuple? x) (pvec? x) (plist? x) (struct? x) (phm? x) (set? x) (lazy-seq? x))) +# coll? mirrors map?'s strictness for structs/tables, and includes the sorted +# collections and records (IPersistentCollection in Clojure). +(defn core-coll? [x] + (or (array? x) (tuple? x) (pvec? x) (plist? x) (phm? x) (set? x) (lazy-seq? x) + (and (struct? x) (nil? (get x :jolt/type))) + (and (table? x) + (or (not (nil? (get x :jolt/deftype))) + (= :jolt/sorted-map (get x :jolt/type)) + (= :jolt/sorted-set (get x :jolt/type)))))) (defn core-true? [x] (= true x)) (defn core-false? [x] (= false x)) diff --git a/test/integration/clojure-test-suite-test.janet b/test/integration/clojure-test-suite-test.janet index bba8c09..5891f1f 100644 --- a/test/integration/clojure-test-suite-test.janet +++ b/test/integration/clojure-test-suite-test.janet @@ -43,9 +43,9 @@ # Raised 4004 -> 4034 / clean 66 -> 67 porting partition-all + repeatedly to the # overlay, which required fixing two leniencies (a char is not callable; take # validates its count) — correct beyond those fns, so the suite rose broadly. -(def baseline-pass 4074) +(def baseline-pass 4081) # A file is "clean" when it ran with zero failures AND zero errors. -(def baseline-clean-files 71) +(def baseline-clean-files 72) # Per-file wall-clock budget (seconds). Normal files finish in well under 1s, so # this normally only fires on genuinely-infinite-sequence hangs. It's an env var # (JOLT_SUITE_TIMEOUT) so CI — whose runners are slower than a dev machine — can diff --git a/test/spec/predicates-spec.janet b/test/spec/predicates-spec.janet index e1a860c..dd42db0 100644 --- a/test/spec/predicates-spec.janet +++ b/test/spec/predicates-spec.janet @@ -90,6 +90,33 @@ # Tagged-value predicates moved to the overlay in Phase 4 (read the value's # :jolt/type via get). The constructors stay native. +# map?/coll? are STRICT (jolt-6s2 cleanup): tagged structs (symbols, chars, +# uuids) are values, not collections; sorted maps/sets and records ARE +# collections (and sorted-map/record are map?), matching Clojure. +(defspec "predicates / map? & coll? strictness" + ["map? symbol" "false" "(map? (quote sym))"] + ["map? char" "false" "(map? \\a)"] + ["map? uuid" "false" "(map? (random-uuid))"] + ["map? literal" "true" "(map? {:a 1})"] + ["map? hash-map" "true" "(map? (hash-map :a 1))"] + ["map? sorted-map" "true" "(map? (sorted-map :a 1))"] + ["map? record" "true" "(do (defrecord Mr [a]) (map? (->Mr 1)))"] + ["map? sorted-set" "false" "(map? (sorted-set 1))"] + ["map? vector" "false" "(map? [1])"] + ["coll? symbol" "false" "(coll? (quote sym))"] + ["coll? char" "false" "(coll? \\a)"] + ["coll? uuid" "false" "(coll? (random-uuid))"] + ["coll? keyword" "false" "(coll? :k)"] + ["coll? string" "false" "(coll? \"s\")"] + ["coll? map literal" "true" "(coll? {:a 1})"] + ["coll? sorted-map" "true" "(coll? (sorted-map :a 1))"] + ["coll? sorted-set" "true" "(coll? (sorted-set 1))"] + ["coll? record" "true" "(do (defrecord Cr [a]) (coll? (->Cr 1)))"] + ["coll? vector" "true" "(coll? [1])"] + ["coll? list" "true" "(coll? (list 1))"] + ["coll? set" "true" "(coll? #{1})"] + ["coll? lazy seq" "true" "(coll? (map inc [1]))"]) + (defspec "predicates / tagged-value (Phase 4)" ["atom? yes" "true" "(atom? (atom 1))"] ["atom? no" "false" "(atom? 1)"]