To my surprise I found an easy solution.
(defmacro q [code]
(cond (symbol? code) (list 'quote code)
(number? code) code
(string? code) code
(keyword? code) code
(vector? code) (apply vector (map #(list `q %) code))
(map? code) (update-keys (update-vals code #(list `q %)) #(list `q %))
(and (list? code) (= (first code) 'uq)) (second code)
(list? code) (apply list 'list (map #(list `q %) code))))
(comment
(q 4)
(q b)
(q "abc")
(q ())
(q [])
(q (a))
(q (a b))
(q ({a b}))
(q {a b})
(q [a b c])
(q (a [b c d] e))
(q (a (b c d) e))
(q (a (uq (+ 1 1)) b))
(let [x 'b] (q 4))
(let [x 'b] (q (uq x)))
(let [x 'b] (q (a (uq x))))
(let [x 'b] (q ({a (uq x)})))
(let [x 'b] (q {a (uq x)}))
(let [x 'b] (q [a (uq x) c]))
(let [x 'b] (q (a [(uq x) c d] e)))
(let [x 'b] (q (a ((uq x) c d) e)))
(let [x 'b] (q ({a (uq x) c d} e)))
(let [x 'b] (q (uq (map identity ['a (q ((uq x) c))])))))
The macro q quotes something and uq is unquote. It seems to work.