Skip to content

Instantly share code, notes, and snippets.

@yogthos
Created December 18, 2013 16:28
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save yogthos/8025281 to your computer and use it in GitHub Desktop.
Save yogthos/8025281 to your computer and use it in GitHub Desktop.
(ns parser)
(defn read-char [rdr]
(let [ch (.read rdr)]
(if-not (== -1 ch) (char ch))))
(def expr-tags
{:if #(str "if tag args: " (clojure.string/join ", " %1))})
(defn expr-tag [{:keys [tag-name args] :as tag} rdr]
(if-let [handler (get expr-tags tag-name)]
(handler args)
(throw (Exception. (str "unrecognized tag: " tag-name)))))
(defn filter-tag [{:keys [tag-value]}]
(str "filter tag value: " tag-value))
(defn read-tag-info [rdr]
(let [buf (StringBuilder.)
tag-type (if (= \{ (read-char rdr)) :filter :expr)]
(loop [ch1 (read-char rdr)
ch2 (read-char rdr)]
(when-not (and (or (= \} ch1) (= \% ch1))
(= \} ch2))
(.append buf ch1)
(recur ch2 (read-char rdr))))
(let [content (->> (.split (.toString buf ) " ") (remove empty?) (map (memfn trim)))]
(merge {:tag-type tag-type}
(if (= :filter tag-type)
{:tag-value (first content)}
{:tag-name (keyword (first content))
:args (rest content)})))))
(defn parse-tag [{:keys [tag-type] :as tag} rdr]
(if (= :filter tag-type)
(filter-tag tag)
(expr-tag tag rdr)))
(defn handle-tag [rdr]
(let [tag (read-tag-info rdr)]
(parse-tag tag rdr)))
(defn parse [file]
(with-open [rdr (clojure.java.io/reader file)]
(let [template (transient [])
buf (StringBuilder.)]
(loop [ch (read-char rdr)]
(when ch
(if (= \{ ch)
(do
(conj! template (.toString buf))
(.setLength buf 0)
(conj! template (handle-tag rdr))
(recur (read-char rdr)))
(do
(.append buf ch)
(recur (read-char rdr))))))
(conj! template (.toString buf))
(persistent! template))))
(defn render [template args]
(let [buf (StringBuilder.)]
(doseq [element template]
(when element
(.append buf (if (string? element) element (element args)))))
(.toString buf)))
(defn render-file [filename args]
(render (parse filename) args))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment