From 5cd8d15ae7d677e088789ed9a3cd6e16b3f6624c Mon Sep 17 00:00:00 2001 From: Yogthos Date: Fri, 26 Jun 2026 22:42:19 -0400 Subject: [PATCH] A set literal reaches a macro as a set value MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #{...} reads as the tagged set-form for the analyzer, but a macro saw that map instead of a set (set? false / map? true, unlike a vector). hc-expand-1 now converts a set-form argument to a real set before calling the expander, so (set? arg)/conj/seq work — hiccup's compiler introspects a literal set this way (str (html #{"<>"}) was empty, now #{"<>"}). Elements stay as read; a deeply-nested set literal inside another form is left for the analyzer. hiccup 382->383. Jolt-side unit guards (macro def+use in one form isn't JVM-portable). --- host/chez/host-contract.ss | 14 +++++++++++++- test/chez/unit.edn | 3 +++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/host/chez/host-contract.ss b/host/chez/host-contract.ss index b01f716..b994dd1 100644 --- a/host/chez/host-contract.ss +++ b/host/chez/host-contract.ss @@ -203,10 +203,22 @@ dst)) dst)) +;; A set literal reads as the tagged set-form {:jolt/type :jolt/set :value [...]} +;; for the analyzer, but a macro must see a real set value (Clojure parity, so +;; (set? arg) / seq / conj work — hiccup's compiler does this). Convert a set-form +;; argument to a set; elements stay as read (a deeply-nested set literal inside +;; another form is rarer and left for the analyzer). +(define (hc-macro-arg x) + (if (rdr-set-form? x) + (let ((items (jolt-get x rdr-kw-value))) + (let loop ((i 0) (s empty-pset)) + (if (fx>=? i (pvec-count items)) s + (loop (fx+ i 1) (pset-conj s (pvec-nth-d items i jolt-nil)))))) + x)) (define (hc-expand-1 ctx form) (let* ((items (seq->list form)) (head (car items)) - (args (cdr items)) + (args (map hc-macro-arg (cdr items))) (expander (var-cell-root (hc-resolve-cell ctx head)))) (hc-propagate-pos form (apply jolt-invoke expander args)))) diff --git a/test/chez/unit.edn b/test/chez/unit.edn index 5e85d49..5cb28eb 100644 --- a/test/chez/unit.edn +++ b/test/chez/unit.edn @@ -567,4 +567,7 @@ {:suite "deftype-map" :expr "(do (deftype Op [s]) [(map? (->Op 1)) (record? (->Op 1)) (coll? (->Op 1))])" :expected "[false false false]"} {:suite "deftype-map" :expr "(do (deftype Lc [xs] clojure.lang.Counted (count [_] (count xs)) clojure.lang.Seqable (seq [_] (seq xs))) [(coll? (->Lc [1 2])) (count (->Lc [1 2])) (vec (seq (->Lc [1 2])))])" :expected "[true 2 [1 2]]"} {:suite "deftype-map" :expr "(do (defrecord Dr [a b]) [(map? (->Dr 1 2)) (record? (->Dr 1 2)) (coll? (->Dr 1 2))])" :expected "[true true true]"} + {:suite "macro-args" :expr "(do (defmacro sm [x] [(set? x) (map? x)]) (sm #{1 2}))" :expected "[true false]"} + {:suite "macro-args" :expr "(do (defmacro ws [x] (conj x :z)) (= #{1 :z} (ws #{1})))" :expected "true"} + {:suite "macro-args" :expr "(do (defmacro vm [x] (vector? x)) (vm [1 2]))" :expected "true"} ]