Clojureのリードマクロでヒアドキュメント実装してみた

公式にはリードマクロは使えない事になっているようだが、怪しい事をすればいけるらしい。
http://briancarper.net/blog/clojure-reader-macros
そういうわけで、ヒアドキュメントを実装してみた。

(defn dispatch-reader-macro [ch fun]
  (let [dm (.get (doto (.getDeclaredField clojure.lang.LispReader "dispatchMacros")
                   (.setAccessible true))
                 nil)]
    (aset dm (int ch) fun)))
; http://java.sun.com/j2se/1.3/ja/docs/ja/api/java/lang/reflect/AccessibleObject.html

(defn read-until [reader end]
  (let [end (map int end)]
    (->> (loop [res nil e end]
           (if (empty? e)
             res
             (let [c (.read reader)]
               (recur (conj res c) (if (= c (first e))
                                     (rest e)
                                     end)))))
         (drop (count end)) reverse (map char) (apply str))))

(defn here-document [reader ch]
  (let [end (read-until reader "\n")]
    (read-until reader (apply str (cons \newline end)))))

(dispatch-reader-macro \- here-document)

(=
  "neko\ncat"
  #-EOM
neko
cat
EOM) ;=> true